@eide/foir-cli 0.1.0
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/dist/auth/credentials.d.ts +29 -0
- package/dist/auth/credentials.d.ts.map +1 -0
- package/dist/auth/credentials.js +79 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +74 -0
- package/dist/commands/api-keys.d.ts +4 -0
- package/dist/commands/api-keys.d.ts.map +1 -0
- package/dist/commands/api-keys.js +127 -0
- package/dist/commands/context.d.ts +4 -0
- package/dist/commands/context.d.ts.map +1 -0
- package/dist/commands/context.js +92 -0
- package/dist/commands/customers.d.ts +4 -0
- package/dist/commands/customers.d.ts.map +1 -0
- package/dist/commands/customers.js +120 -0
- package/dist/commands/experiments.d.ts +4 -0
- package/dist/commands/experiments.d.ts.map +1 -0
- package/dist/commands/experiments.js +177 -0
- package/dist/commands/extensions.d.ts +4 -0
- package/dist/commands/extensions.d.ts.map +1 -0
- package/dist/commands/extensions.js +94 -0
- package/dist/commands/files.d.ts +4 -0
- package/dist/commands/files.d.ts.map +1 -0
- package/dist/commands/files.js +143 -0
- package/dist/commands/locales.d.ts +4 -0
- package/dist/commands/locales.d.ts.map +1 -0
- package/dist/commands/locales.js +126 -0
- package/dist/commands/login.d.ts +4 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +125 -0
- package/dist/commands/logout.d.ts +4 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +16 -0
- package/dist/commands/media.d.ts +4 -0
- package/dist/commands/media.d.ts.map +1 -0
- package/dist/commands/media.js +44 -0
- package/dist/commands/models.d.ts +4 -0
- package/dist/commands/models.d.ts.map +1 -0
- package/dist/commands/models.js +155 -0
- package/dist/commands/notes.d.ts +4 -0
- package/dist/commands/notes.d.ts.map +1 -0
- package/dist/commands/notes.js +120 -0
- package/dist/commands/notifications.d.ts +4 -0
- package/dist/commands/notifications.d.ts.map +1 -0
- package/dist/commands/notifications.js +73 -0
- package/dist/commands/operations.d.ts +4 -0
- package/dist/commands/operations.d.ts.map +1 -0
- package/dist/commands/operations.js +161 -0
- package/dist/commands/records.d.ts +4 -0
- package/dist/commands/records.d.ts.map +1 -0
- package/dist/commands/records.js +216 -0
- package/dist/commands/schedules.d.ts +4 -0
- package/dist/commands/schedules.d.ts.map +1 -0
- package/dist/commands/schedules.js +150 -0
- package/dist/commands/search.d.ts +4 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +60 -0
- package/dist/commands/segments.d.ts +4 -0
- package/dist/commands/segments.d.ts.map +1 -0
- package/dist/commands/segments.js +143 -0
- package/dist/commands/select-project.d.ts +4 -0
- package/dist/commands/select-project.d.ts.map +1 -0
- package/dist/commands/select-project.js +144 -0
- package/dist/commands/settings.d.ts +4 -0
- package/dist/commands/settings.d.ts.map +1 -0
- package/dist/commands/settings.js +113 -0
- package/dist/commands/variant-catalog.d.ts +4 -0
- package/dist/commands/variant-catalog.d.ts.map +1 -0
- package/dist/commands/variant-catalog.js +111 -0
- package/dist/commands/whoami.d.ts +4 -0
- package/dist/commands/whoami.d.ts.map +1 -0
- package/dist/commands/whoami.js +50 -0
- package/dist/graphql/queries.d.ts +101 -0
- package/dist/graphql/queries.d.ts.map +1 -0
- package/dist/graphql/queries.js +373 -0
- package/dist/lib/client.d.ts +17 -0
- package/dist/lib/client.d.ts.map +1 -0
- package/dist/lib/client.js +61 -0
- package/dist/lib/config.d.ts +12 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +8 -0
- package/dist/lib/errors.d.ts +6 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +62 -0
- package/dist/lib/input.d.ts +36 -0
- package/dist/lib/input.d.ts.map +1 -0
- package/dist/lib/input.js +106 -0
- package/dist/lib/output.d.ts +31 -0
- package/dist/lib/output.d.ts.map +1 -0
- package/dist/lib/output.js +107 -0
- package/package.json +59 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { withErrorHandler } from '../lib/errors.js';
|
|
2
|
+
import { createClient } from '../lib/client.js';
|
|
3
|
+
import { formatOutput, formatList, timeAgo, success } from '../lib/output.js';
|
|
4
|
+
import { parseInputData } from '../lib/input.js';
|
|
5
|
+
import { OPERATIONS, OPERATION, EXECUTE_OPERATION, OPERATION_EXECUTION_STATS, DEAD_LETTER_OPERATIONS, RETRY_DEAD_LETTER, DISMISS_DEAD_LETTER, } from '../graphql/queries.js';
|
|
6
|
+
export function registerOperationsCommands(program, globalOpts) {
|
|
7
|
+
const operations = program
|
|
8
|
+
.command('operations')
|
|
9
|
+
.description('Manage operations');
|
|
10
|
+
// list
|
|
11
|
+
operations
|
|
12
|
+
.command('list')
|
|
13
|
+
.description('List operations')
|
|
14
|
+
.option('--category <cat>', 'Filter by category')
|
|
15
|
+
.option('--active', 'Only active operations')
|
|
16
|
+
.option('--limit <n>', 'Max results', '50')
|
|
17
|
+
.action(withErrorHandler(globalOpts, async (cmdOpts) => {
|
|
18
|
+
const opts = globalOpts();
|
|
19
|
+
const client = await createClient(opts);
|
|
20
|
+
const data = await client.request(OPERATIONS, {
|
|
21
|
+
category: cmdOpts.category,
|
|
22
|
+
isActive: cmdOpts.active ? true : undefined,
|
|
23
|
+
limit: parseInt(String(cmdOpts.limit ?? '50'), 10),
|
|
24
|
+
});
|
|
25
|
+
formatList(data.operations, opts, {
|
|
26
|
+
columns: [
|
|
27
|
+
{ key: 'key', header: 'Key', width: 24 },
|
|
28
|
+
{ key: 'name', header: 'Name', width: 24 },
|
|
29
|
+
{ key: 'category', header: 'Category', width: 14 },
|
|
30
|
+
{
|
|
31
|
+
key: 'isActive',
|
|
32
|
+
header: 'Active',
|
|
33
|
+
width: 8,
|
|
34
|
+
format: (v) => (v ? 'yes' : 'no'),
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
key: 'updatedAt',
|
|
38
|
+
header: 'Updated',
|
|
39
|
+
width: 12,
|
|
40
|
+
format: (v) => timeAgo(v),
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
});
|
|
44
|
+
}));
|
|
45
|
+
// get
|
|
46
|
+
operations
|
|
47
|
+
.command('get <key>')
|
|
48
|
+
.description('Get an operation by key')
|
|
49
|
+
.action(withErrorHandler(globalOpts, async (key) => {
|
|
50
|
+
const opts = globalOpts();
|
|
51
|
+
const client = await createClient(opts);
|
|
52
|
+
const data = await client.request(OPERATION, { key });
|
|
53
|
+
if (!data.operation)
|
|
54
|
+
throw new Error(`Operation "${key}" not found.`);
|
|
55
|
+
formatOutput(data.operation, opts);
|
|
56
|
+
}));
|
|
57
|
+
// execute
|
|
58
|
+
operations
|
|
59
|
+
.command('execute <key>')
|
|
60
|
+
.description('Execute an operation')
|
|
61
|
+
.option('-d, --data <json>', 'Input data as JSON')
|
|
62
|
+
.option('-f, --file <path>', 'Read input from file')
|
|
63
|
+
.option('--async', 'Execute asynchronously')
|
|
64
|
+
.action(withErrorHandler(globalOpts, async (key, cmdOpts) => {
|
|
65
|
+
const opts = globalOpts();
|
|
66
|
+
const client = await createClient(opts);
|
|
67
|
+
let inputData = {};
|
|
68
|
+
if (cmdOpts.data || cmdOpts.file) {
|
|
69
|
+
inputData = await parseInputData(cmdOpts);
|
|
70
|
+
}
|
|
71
|
+
const data = await client.request(EXECUTE_OPERATION, {
|
|
72
|
+
input: {
|
|
73
|
+
operationKey: key,
|
|
74
|
+
input: inputData,
|
|
75
|
+
async: !!cmdOpts.async,
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
formatOutput(data.executeOperation, opts);
|
|
79
|
+
if (!(opts.json || opts.jsonl || opts.quiet)) {
|
|
80
|
+
const result = data.executeOperation;
|
|
81
|
+
if (result.success) {
|
|
82
|
+
success(`Operation completed in ${result.durationMs}ms`);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
const err = result.error;
|
|
86
|
+
console.error(`Operation failed: ${err?.message ?? 'Unknown error'}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}));
|
|
90
|
+
// stats
|
|
91
|
+
operations
|
|
92
|
+
.command('stats <key>')
|
|
93
|
+
.description('Get execution statistics for an operation')
|
|
94
|
+
.action(withErrorHandler(globalOpts, async (key) => {
|
|
95
|
+
const opts = globalOpts();
|
|
96
|
+
const client = await createClient(opts);
|
|
97
|
+
const data = await client.request(OPERATION_EXECUTION_STATS, { operationKey: key });
|
|
98
|
+
formatOutput(data.operationExecutionStats, opts);
|
|
99
|
+
}));
|
|
100
|
+
// dead-letters
|
|
101
|
+
operations
|
|
102
|
+
.command('dead-letters')
|
|
103
|
+
.description('List failed operations in the dead letter queue')
|
|
104
|
+
.option('--operation <key>', 'Filter by operation key')
|
|
105
|
+
.option('--status <status>', 'Filter by status (PENDING, RETRIED, DISMISSED)')
|
|
106
|
+
.option('--limit <n>', 'Max results', '20')
|
|
107
|
+
.action(withErrorHandler(globalOpts, async (cmdOpts) => {
|
|
108
|
+
const opts = globalOpts();
|
|
109
|
+
const client = await createClient(opts);
|
|
110
|
+
const data = await client.request(DEAD_LETTER_OPERATIONS, {
|
|
111
|
+
operationKey: cmdOpts.operation,
|
|
112
|
+
status: cmdOpts.status,
|
|
113
|
+
limit: parseInt(cmdOpts.limit ?? '20', 10),
|
|
114
|
+
});
|
|
115
|
+
formatList(data.deadLetterOperations.items, opts, {
|
|
116
|
+
columns: [
|
|
117
|
+
{ key: 'id', header: 'ID', width: 28 },
|
|
118
|
+
{ key: 'operationKey', header: 'Operation', width: 20 },
|
|
119
|
+
{ key: 'attempts', header: 'Tries', width: 6 },
|
|
120
|
+
{ key: 'lastError', header: 'Error', width: 36 },
|
|
121
|
+
{ key: 'status', header: 'Status', width: 10 },
|
|
122
|
+
{
|
|
123
|
+
key: 'failedAt',
|
|
124
|
+
header: 'Failed',
|
|
125
|
+
width: 12,
|
|
126
|
+
format: (v) => timeAgo(v),
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
total: data.deadLetterOperations.total,
|
|
130
|
+
});
|
|
131
|
+
}));
|
|
132
|
+
// retry-dead-letter
|
|
133
|
+
operations
|
|
134
|
+
.command('retry-dead-letter <id>')
|
|
135
|
+
.description('Retry a failed dead letter operation')
|
|
136
|
+
.action(withErrorHandler(globalOpts, async (id) => {
|
|
137
|
+
const opts = globalOpts();
|
|
138
|
+
const client = await createClient(opts);
|
|
139
|
+
const data = await client.request(RETRY_DEAD_LETTER, { id });
|
|
140
|
+
formatOutput(data.retryDeadLetterOperation, opts);
|
|
141
|
+
if (!(opts.json || opts.jsonl || opts.quiet)) {
|
|
142
|
+
const r = data.retryDeadLetterOperation;
|
|
143
|
+
if (r.success)
|
|
144
|
+
success('Retry succeeded');
|
|
145
|
+
else
|
|
146
|
+
console.error('Retry failed');
|
|
147
|
+
}
|
|
148
|
+
}));
|
|
149
|
+
// dismiss-dead-letter
|
|
150
|
+
operations
|
|
151
|
+
.command('dismiss-dead-letter <id>')
|
|
152
|
+
.description('Dismiss a dead letter operation without retrying')
|
|
153
|
+
.action(withErrorHandler(globalOpts, async (id) => {
|
|
154
|
+
const opts = globalOpts();
|
|
155
|
+
const client = await createClient(opts);
|
|
156
|
+
const data = await client.request(DISMISS_DEAD_LETTER, { id });
|
|
157
|
+
formatOutput(data.dismissDeadLetterOperation, opts);
|
|
158
|
+
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
159
|
+
success(`Dismissed dead letter ${id}`);
|
|
160
|
+
}));
|
|
161
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"records.d.ts","sourceRoot":"","sources":["../../src/commands/records.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAyBtD,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,aAAa,GAC9B,IAAI,CA+SN"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { withErrorHandler } from '../lib/errors.js';
|
|
2
|
+
import { createClient } from '../lib/client.js';
|
|
3
|
+
import { formatOutput, formatList, timeAgo, success } from '../lib/output.js';
|
|
4
|
+
import { parseInputData, parseFilters, parseSort, isUUID, confirmAction, } from '../lib/input.js';
|
|
5
|
+
import { RECORDS, RECORD, RECORD_BY_KEY, CREATE_RECORD, UPDATE_RECORD, DELETE_RECORD, PUBLISH_VERSION, UNPUBLISH_RECORD, DUPLICATE_RECORD, RECORD_VERSIONS, RECORD_VARIANTS, } from '../graphql/queries.js';
|
|
6
|
+
export function registerRecordsCommands(program, globalOpts) {
|
|
7
|
+
const records = program.command('records').description('Manage records');
|
|
8
|
+
// list
|
|
9
|
+
records
|
|
10
|
+
.command('list <modelKey>')
|
|
11
|
+
.description('List records for a model')
|
|
12
|
+
.option('--filter <expr>', 'Filter expression (e.g. status=active)')
|
|
13
|
+
.option('--sort <expr>', 'Sort expression (e.g. createdAt:desc)')
|
|
14
|
+
.option('--limit <n>', 'Max results', '20')
|
|
15
|
+
.option('--offset <n>', 'Skip results', '0')
|
|
16
|
+
.action(withErrorHandler(globalOpts, async (modelKey, cmdOpts) => {
|
|
17
|
+
const opts = globalOpts();
|
|
18
|
+
const client = await createClient(opts);
|
|
19
|
+
const variables = {
|
|
20
|
+
modelKey,
|
|
21
|
+
limit: parseInt(cmdOpts.limit ?? '20', 10),
|
|
22
|
+
offset: parseInt(cmdOpts.offset ?? '0', 10),
|
|
23
|
+
};
|
|
24
|
+
if (cmdOpts.filter)
|
|
25
|
+
variables.filters = parseFilters(cmdOpts.filter);
|
|
26
|
+
if (cmdOpts.sort)
|
|
27
|
+
variables.sort = parseSort(cmdOpts.sort);
|
|
28
|
+
const data = await client.request(RECORDS, variables);
|
|
29
|
+
formatList(data.records.items, opts, {
|
|
30
|
+
columns: [
|
|
31
|
+
{ key: 'id', header: 'ID', width: 28 },
|
|
32
|
+
{ key: 'naturalKey', header: 'Key', width: 24 },
|
|
33
|
+
{ key: 'recordType', header: 'Type', width: 10 },
|
|
34
|
+
{ key: 'publishStatus', header: 'Status', width: 12 },
|
|
35
|
+
{
|
|
36
|
+
key: 'updatedAt',
|
|
37
|
+
header: 'Updated',
|
|
38
|
+
width: 12,
|
|
39
|
+
format: (v) => timeAgo(v),
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
total: data.records.total,
|
|
43
|
+
});
|
|
44
|
+
}));
|
|
45
|
+
// get
|
|
46
|
+
records
|
|
47
|
+
.command('get <modelKey> <idOrKey>')
|
|
48
|
+
.description('Get a record by ID or natural key')
|
|
49
|
+
.action(withErrorHandler(globalOpts, async (modelKey, idOrKey) => {
|
|
50
|
+
const opts = globalOpts();
|
|
51
|
+
const client = await createClient(opts);
|
|
52
|
+
let result;
|
|
53
|
+
if (isUUID(idOrKey)) {
|
|
54
|
+
const data = await client.request(RECORD, { id: idOrKey });
|
|
55
|
+
result = data.record;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
const data = await client.request(RECORD_BY_KEY, { modelKey, naturalKey: idOrKey });
|
|
59
|
+
result = data.recordByKey;
|
|
60
|
+
}
|
|
61
|
+
if (!result) {
|
|
62
|
+
throw new Error(`Record "${idOrKey}" not found in model "${modelKey}".`);
|
|
63
|
+
}
|
|
64
|
+
formatOutput(result, opts);
|
|
65
|
+
}));
|
|
66
|
+
// create
|
|
67
|
+
records
|
|
68
|
+
.command('create <modelKey>')
|
|
69
|
+
.description('Create a new record')
|
|
70
|
+
.option('-d, --data <json>', 'Record data as JSON')
|
|
71
|
+
.option('-f, --file <path>', 'Read data from file')
|
|
72
|
+
.action(withErrorHandler(globalOpts, async (modelKey, cmdOpts) => {
|
|
73
|
+
const opts = globalOpts();
|
|
74
|
+
const client = await createClient(opts);
|
|
75
|
+
const inputData = await parseInputData(cmdOpts);
|
|
76
|
+
const input = { modelKey, ...inputData };
|
|
77
|
+
const data = await client.request(CREATE_RECORD, { input });
|
|
78
|
+
formatOutput(data.createRecord, opts);
|
|
79
|
+
if (!(opts.json || opts.jsonl || opts.quiet)) {
|
|
80
|
+
success(`Created record ${data.createRecord.record.id}`);
|
|
81
|
+
}
|
|
82
|
+
}));
|
|
83
|
+
// update
|
|
84
|
+
records
|
|
85
|
+
.command('update <modelKey> <id>')
|
|
86
|
+
.description('Update a record')
|
|
87
|
+
.option('-d, --data <json>', 'Record data as JSON')
|
|
88
|
+
.option('-f, --file <path>', 'Read data from file')
|
|
89
|
+
.action(withErrorHandler(globalOpts, async (_modelKey, id, cmdOpts) => {
|
|
90
|
+
const opts = globalOpts();
|
|
91
|
+
const client = await createClient(opts);
|
|
92
|
+
const inputData = await parseInputData(cmdOpts);
|
|
93
|
+
const input = { id, ...inputData };
|
|
94
|
+
const data = await client.request(UPDATE_RECORD, { input });
|
|
95
|
+
formatOutput(data.updateRecord, opts);
|
|
96
|
+
if (!(opts.json || opts.jsonl || opts.quiet)) {
|
|
97
|
+
success(`Updated record ${id}`);
|
|
98
|
+
}
|
|
99
|
+
}));
|
|
100
|
+
// delete
|
|
101
|
+
records
|
|
102
|
+
.command('delete <modelKey> <id>')
|
|
103
|
+
.description('Delete a record')
|
|
104
|
+
.option('--confirm', 'Skip confirmation prompt')
|
|
105
|
+
.action(withErrorHandler(globalOpts, async (_modelKey, id, cmdOpts) => {
|
|
106
|
+
const opts = globalOpts();
|
|
107
|
+
const confirmed = await confirmAction(`Delete record ${id}?`, {
|
|
108
|
+
confirm: !!cmdOpts.confirm,
|
|
109
|
+
});
|
|
110
|
+
if (!confirmed) {
|
|
111
|
+
console.log('Aborted.');
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const client = await createClient(opts);
|
|
115
|
+
const data = await client.request(DELETE_RECORD, { id });
|
|
116
|
+
formatOutput(data.deleteRecord, opts);
|
|
117
|
+
if (!(opts.json || opts.jsonl || opts.quiet)) {
|
|
118
|
+
success(`Deleted record ${id}`);
|
|
119
|
+
}
|
|
120
|
+
}));
|
|
121
|
+
// publish
|
|
122
|
+
records
|
|
123
|
+
.command('publish <versionId>')
|
|
124
|
+
.description('Publish a record version')
|
|
125
|
+
.action(withErrorHandler(globalOpts, async (versionId) => {
|
|
126
|
+
const opts = globalOpts();
|
|
127
|
+
const client = await createClient(opts);
|
|
128
|
+
await client.request(PUBLISH_VERSION, { versionId });
|
|
129
|
+
if (opts.json || opts.jsonl) {
|
|
130
|
+
formatOutput({ published: true, versionId }, opts);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
success(`Published version ${versionId}`);
|
|
134
|
+
}
|
|
135
|
+
}));
|
|
136
|
+
// unpublish
|
|
137
|
+
records
|
|
138
|
+
.command('unpublish <id>')
|
|
139
|
+
.description('Unpublish a record')
|
|
140
|
+
.action(withErrorHandler(globalOpts, async (id) => {
|
|
141
|
+
const opts = globalOpts();
|
|
142
|
+
const client = await createClient(opts);
|
|
143
|
+
await client.request(UNPUBLISH_RECORD, { id });
|
|
144
|
+
if (opts.json || opts.jsonl) {
|
|
145
|
+
formatOutput({ unpublished: true, id }, opts);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
success(`Unpublished record ${id}`);
|
|
149
|
+
}
|
|
150
|
+
}));
|
|
151
|
+
// duplicate
|
|
152
|
+
records
|
|
153
|
+
.command('duplicate <modelKey> <id>')
|
|
154
|
+
.description('Duplicate a record')
|
|
155
|
+
.option('--natural-key <key>', 'Natural key for the duplicate')
|
|
156
|
+
.action(withErrorHandler(globalOpts, async (_modelKey, id, cmdOpts) => {
|
|
157
|
+
const opts = globalOpts();
|
|
158
|
+
const client = await createClient(opts);
|
|
159
|
+
const naturalKey = cmdOpts.naturalKey ?? `${id}-copy`;
|
|
160
|
+
const data = await client.request(DUPLICATE_RECORD, { input: { recordId: id, naturalKey } });
|
|
161
|
+
formatOutput(data.duplicateRecord, opts);
|
|
162
|
+
if (!(opts.json || opts.jsonl || opts.quiet)) {
|
|
163
|
+
success(`Duplicated → ${data.duplicateRecord.record.id}`);
|
|
164
|
+
}
|
|
165
|
+
}));
|
|
166
|
+
// versions
|
|
167
|
+
records
|
|
168
|
+
.command('versions <id>')
|
|
169
|
+
.description('List versions for a record')
|
|
170
|
+
.option('--limit <n>', 'Max results', '20')
|
|
171
|
+
.action(withErrorHandler(globalOpts, async (parentId, cmdOpts) => {
|
|
172
|
+
const opts = globalOpts();
|
|
173
|
+
const client = await createClient(opts);
|
|
174
|
+
const data = await client.request(RECORD_VERSIONS, {
|
|
175
|
+
parentId,
|
|
176
|
+
limit: parseInt(cmdOpts.limit ?? '20', 10),
|
|
177
|
+
});
|
|
178
|
+
formatList(data.recordVersions.items, opts, {
|
|
179
|
+
columns: [
|
|
180
|
+
{ key: 'id', header: 'Version ID', width: 28 },
|
|
181
|
+
{ key: 'versionNumber', header: '#', width: 5 },
|
|
182
|
+
{ key: 'publishStatus', header: 'Status', width: 12 },
|
|
183
|
+
{ key: 'changeDescription', header: 'Description', width: 30 },
|
|
184
|
+
{
|
|
185
|
+
key: 'createdAt',
|
|
186
|
+
header: 'Created',
|
|
187
|
+
width: 12,
|
|
188
|
+
format: (v) => timeAgo(v),
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
});
|
|
192
|
+
}));
|
|
193
|
+
// variants
|
|
194
|
+
records
|
|
195
|
+
.command('variants <recordId>')
|
|
196
|
+
.description('List variants for a record')
|
|
197
|
+
.action(withErrorHandler(globalOpts, async (recordId) => {
|
|
198
|
+
const opts = globalOpts();
|
|
199
|
+
const client = await createClient(opts);
|
|
200
|
+
const data = await client.request(RECORD_VARIANTS, { recordId });
|
|
201
|
+
formatList(data.recordVariants.items, opts, {
|
|
202
|
+
columns: [
|
|
203
|
+
{ key: 'id', header: 'Variant ID', width: 28 },
|
|
204
|
+
{ key: 'variantKey', header: 'Key', width: 20 },
|
|
205
|
+
{ key: 'variantName', header: 'Name', width: 20 },
|
|
206
|
+
{ key: 'isDefault', header: 'Default', width: 8 },
|
|
207
|
+
{
|
|
208
|
+
key: 'createdAt',
|
|
209
|
+
header: 'Created',
|
|
210
|
+
width: 12,
|
|
211
|
+
format: (v) => timeAgo(v),
|
|
212
|
+
},
|
|
213
|
+
],
|
|
214
|
+
});
|
|
215
|
+
}));
|
|
216
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schedules.d.ts","sourceRoot":"","sources":["../../src/commands/schedules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAgBtD,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,aAAa,GAC9B,IAAI,CA4LN"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { withErrorHandler } from '../lib/errors.js';
|
|
2
|
+
import { createClient } from '../lib/client.js';
|
|
3
|
+
import { formatOutput, formatList, timeAgo, success } from '../lib/output.js';
|
|
4
|
+
import { parseInputData, confirmAction } from '../lib/input.js';
|
|
5
|
+
import { SCHEDULES, SCHEDULE, CREATE_SCHEDULE, UPDATE_SCHEDULE, DELETE_SCHEDULE, PAUSE_SCHEDULE, RESUME_SCHEDULE, TRIGGER_SCHEDULE, } from '../graphql/queries.js';
|
|
6
|
+
export function registerSchedulesCommands(program, globalOpts) {
|
|
7
|
+
const schedules = program
|
|
8
|
+
.command('schedules')
|
|
9
|
+
.description('Manage schedules');
|
|
10
|
+
// list
|
|
11
|
+
schedules
|
|
12
|
+
.command('list')
|
|
13
|
+
.description('List schedules')
|
|
14
|
+
.option('--active', 'Only active schedules')
|
|
15
|
+
.option('--limit <n>', 'Max results', '50')
|
|
16
|
+
.action(withErrorHandler(globalOpts, async (cmdOpts) => {
|
|
17
|
+
const opts = globalOpts();
|
|
18
|
+
const client = await createClient(opts);
|
|
19
|
+
const data = await client.request(SCHEDULES, {
|
|
20
|
+
isActive: cmdOpts.active ? true : undefined,
|
|
21
|
+
limit: parseInt(String(cmdOpts.limit ?? '50'), 10),
|
|
22
|
+
});
|
|
23
|
+
formatList(data.schedules.items, opts, {
|
|
24
|
+
columns: [
|
|
25
|
+
{ key: 'key', header: 'Key', width: 20 },
|
|
26
|
+
{ key: 'name', header: 'Name', width: 24 },
|
|
27
|
+
{ key: 'cron', header: 'Cron', width: 16 },
|
|
28
|
+
{
|
|
29
|
+
key: 'isActive',
|
|
30
|
+
header: 'Active',
|
|
31
|
+
width: 8,
|
|
32
|
+
format: (v) => (v ? 'yes' : 'no'),
|
|
33
|
+
},
|
|
34
|
+
{ key: 'lastRunStatus', header: 'Last Run', width: 10 },
|
|
35
|
+
{
|
|
36
|
+
key: 'nextRunAt',
|
|
37
|
+
header: 'Next Run',
|
|
38
|
+
width: 12,
|
|
39
|
+
format: (v) => timeAgo(v),
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
total: data.schedules.total,
|
|
43
|
+
});
|
|
44
|
+
}));
|
|
45
|
+
// get
|
|
46
|
+
schedules
|
|
47
|
+
.command('get <key>')
|
|
48
|
+
.description('Get a schedule by key')
|
|
49
|
+
.action(withErrorHandler(globalOpts, async (key) => {
|
|
50
|
+
const opts = globalOpts();
|
|
51
|
+
const client = await createClient(opts);
|
|
52
|
+
const data = await client.request(SCHEDULE, { key });
|
|
53
|
+
if (!data.schedule)
|
|
54
|
+
throw new Error(`Schedule "${key}" not found.`);
|
|
55
|
+
formatOutput(data.schedule, opts);
|
|
56
|
+
}));
|
|
57
|
+
// create
|
|
58
|
+
schedules
|
|
59
|
+
.command('create')
|
|
60
|
+
.description('Create a new schedule')
|
|
61
|
+
.option('-d, --data <json>', 'Schedule data as JSON')
|
|
62
|
+
.option('-f, --file <path>', 'Read data from file')
|
|
63
|
+
.action(withErrorHandler(globalOpts, async (cmdOpts) => {
|
|
64
|
+
const opts = globalOpts();
|
|
65
|
+
const client = await createClient(opts);
|
|
66
|
+
const input = await parseInputData(cmdOpts);
|
|
67
|
+
const data = await client.request(CREATE_SCHEDULE, { input });
|
|
68
|
+
formatOutput(data.createSchedule, opts);
|
|
69
|
+
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
70
|
+
success(`Created schedule ${data.createSchedule.key}`);
|
|
71
|
+
}));
|
|
72
|
+
// update
|
|
73
|
+
schedules
|
|
74
|
+
.command('update <key>')
|
|
75
|
+
.description('Update an existing schedule')
|
|
76
|
+
.option('-d, --data <json>', 'Schedule data as JSON')
|
|
77
|
+
.option('-f, --file <path>', 'Read data from file')
|
|
78
|
+
.action(withErrorHandler(globalOpts, async (key, cmdOpts) => {
|
|
79
|
+
const opts = globalOpts();
|
|
80
|
+
const client = await createClient(opts);
|
|
81
|
+
const input = await parseInputData(cmdOpts);
|
|
82
|
+
const data = await client.request(UPDATE_SCHEDULE, { key, input });
|
|
83
|
+
formatOutput(data.updateSchedule, opts);
|
|
84
|
+
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
85
|
+
success(`Updated schedule "${key}"`);
|
|
86
|
+
}));
|
|
87
|
+
// trigger
|
|
88
|
+
schedules
|
|
89
|
+
.command('trigger <key>')
|
|
90
|
+
.description('Trigger a schedule immediately')
|
|
91
|
+
.action(withErrorHandler(globalOpts, async (key) => {
|
|
92
|
+
const opts = globalOpts();
|
|
93
|
+
const client = await createClient(opts);
|
|
94
|
+
const data = await client.request(TRIGGER_SCHEDULE, { key });
|
|
95
|
+
if (opts.json || opts.jsonl) {
|
|
96
|
+
formatOutput(data.triggerSchedule, opts);
|
|
97
|
+
}
|
|
98
|
+
else if (data.triggerSchedule.success) {
|
|
99
|
+
success(`Triggered schedule "${key}" (job: ${data.triggerSchedule.jobId ?? 'n/a'})`);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
throw new Error(data.triggerSchedule.error ?? 'Trigger failed');
|
|
103
|
+
}
|
|
104
|
+
}));
|
|
105
|
+
// pause
|
|
106
|
+
schedules
|
|
107
|
+
.command('pause <key>')
|
|
108
|
+
.description('Pause a schedule')
|
|
109
|
+
.action(withErrorHandler(globalOpts, async (key) => {
|
|
110
|
+
const opts = globalOpts();
|
|
111
|
+
const client = await createClient(opts);
|
|
112
|
+
const data = await client.request(PAUSE_SCHEDULE, { key });
|
|
113
|
+
formatOutput(data.pauseSchedule, opts);
|
|
114
|
+
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
115
|
+
success(`Paused schedule "${key}"`);
|
|
116
|
+
}));
|
|
117
|
+
// resume
|
|
118
|
+
schedules
|
|
119
|
+
.command('resume <key>')
|
|
120
|
+
.description('Resume a paused schedule')
|
|
121
|
+
.action(withErrorHandler(globalOpts, async (key) => {
|
|
122
|
+
const opts = globalOpts();
|
|
123
|
+
const client = await createClient(opts);
|
|
124
|
+
const data = await client.request(RESUME_SCHEDULE, { key });
|
|
125
|
+
formatOutput(data.resumeSchedule, opts);
|
|
126
|
+
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
127
|
+
success(`Resumed schedule "${key}"`);
|
|
128
|
+
}));
|
|
129
|
+
// delete
|
|
130
|
+
schedules
|
|
131
|
+
.command('delete <key>')
|
|
132
|
+
.description('Delete a schedule')
|
|
133
|
+
.option('--confirm', 'Skip confirmation prompt')
|
|
134
|
+
.action(withErrorHandler(globalOpts, async (key, cmdOpts) => {
|
|
135
|
+
const opts = globalOpts();
|
|
136
|
+
const confirmed = await confirmAction(`Delete schedule "${key}"?`, {
|
|
137
|
+
confirm: !!cmdOpts.confirm,
|
|
138
|
+
});
|
|
139
|
+
if (!confirmed) {
|
|
140
|
+
console.log('Aborted.');
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const client = await createClient(opts);
|
|
144
|
+
await client.request(DELETE_SCHEDULE, { key });
|
|
145
|
+
if (opts.json || opts.jsonl)
|
|
146
|
+
formatOutput({ deleted: true, key }, opts);
|
|
147
|
+
else
|
|
148
|
+
success(`Deleted schedule "${key}"`);
|
|
149
|
+
}));
|
|
150
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/commands/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAMtD,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,aAAa,GAC9B,IAAI,CA6EN"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { withErrorHandler } from '../lib/errors.js';
|
|
2
|
+
import { createClient } from '../lib/client.js';
|
|
3
|
+
import { formatOutput, formatList, timeAgo } from '../lib/output.js';
|
|
4
|
+
import { GLOBAL_SEARCH } from '../graphql/queries.js';
|
|
5
|
+
export function registerSearchCommands(program, globalOpts) {
|
|
6
|
+
program
|
|
7
|
+
.command('search <query>')
|
|
8
|
+
.description('Search across all records and media')
|
|
9
|
+
.option('--models <keys>', 'Filter to specific model keys (comma-separated)')
|
|
10
|
+
.option('--limit <n>', 'Max results', '20')
|
|
11
|
+
.option('--no-media', 'Exclude media results')
|
|
12
|
+
.action(withErrorHandler(globalOpts, async (query, cmdOpts) => {
|
|
13
|
+
const opts = globalOpts();
|
|
14
|
+
const client = await createClient(opts);
|
|
15
|
+
const modelKeys = typeof cmdOpts.models === 'string'
|
|
16
|
+
? cmdOpts.models.split(',').map((k) => k.trim())
|
|
17
|
+
: undefined;
|
|
18
|
+
const data = await client.request(GLOBAL_SEARCH, {
|
|
19
|
+
query,
|
|
20
|
+
limit: parseInt(String(cmdOpts.limit ?? '20'), 10),
|
|
21
|
+
modelKeys,
|
|
22
|
+
includeMedia: cmdOpts.media !== false,
|
|
23
|
+
});
|
|
24
|
+
if (opts.json || opts.jsonl) {
|
|
25
|
+
formatOutput(data.globalSearch, opts);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (data.globalSearch.records.length > 0) {
|
|
29
|
+
console.log(`\nRecords (${data.globalSearch.records.length}):`);
|
|
30
|
+
formatList(data.globalSearch.records, opts, {
|
|
31
|
+
columns: [
|
|
32
|
+
{ key: 'id', header: 'ID', width: 28 },
|
|
33
|
+
{ key: 'modelKey', header: 'Model', width: 18 },
|
|
34
|
+
{ key: 'title', header: 'Title', width: 28 },
|
|
35
|
+
{ key: 'naturalKey', header: 'Key', width: 20 },
|
|
36
|
+
{
|
|
37
|
+
key: 'updatedAt',
|
|
38
|
+
header: 'Updated',
|
|
39
|
+
width: 12,
|
|
40
|
+
format: (v) => timeAgo(v),
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
if (data.globalSearch.media.length > 0) {
|
|
46
|
+
console.log(`\nMedia (${data.globalSearch.media.length}):`);
|
|
47
|
+
formatList(data.globalSearch.media, opts, {
|
|
48
|
+
columns: [
|
|
49
|
+
{ key: 'id', header: 'ID', width: 28 },
|
|
50
|
+
{ key: 'fileName', header: 'File', width: 30 },
|
|
51
|
+
{ key: 'altText', header: 'Alt', width: 24 },
|
|
52
|
+
],
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
if (data.globalSearch.records.length === 0 &&
|
|
56
|
+
data.globalSearch.media.length === 0) {
|
|
57
|
+
console.log('No results found.');
|
|
58
|
+
}
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"segments.d.ts","sourceRoot":"","sources":["../../src/commands/segments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAgBtD,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,aAAa,GAC9B,IAAI,CAqLN"}
|