@burdenoff/bigconsole-cli 2026.802.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 +9 -0
- package/README.md +235 -0
- package/dist/auth/device-code.d.ts +66 -0
- package/dist/auth/device-code.js +239 -0
- package/dist/auth/store.d.ts +46 -0
- package/dist/auth/store.js +90 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +126 -0
- package/dist/commands/auth.d.ts +5 -0
- package/dist/commands/auth.js +352 -0
- package/dist/commands/base.d.ts +47 -0
- package/dist/commands/base.js +100 -0
- package/dist/commands/cli-config.d.ts +6 -0
- package/dist/commands/cli-config.js +79 -0
- package/dist/commands/dashboard.d.ts +5 -0
- package/dist/commands/dashboard.js +220 -0
- package/dist/commands/datasink.d.ts +5 -0
- package/dist/commands/datasink.js +175 -0
- package/dist/commands/drilldown.d.ts +9 -0
- package/dist/commands/drilldown.js +47 -0
- package/dist/commands/index.d.ts +13 -0
- package/dist/commands/index.js +13 -0
- package/dist/commands/parser.d.ts +5 -0
- package/dist/commands/parser.js +181 -0
- package/dist/commands/pipeline.d.ts +5 -0
- package/dist/commands/pipeline.js +142 -0
- package/dist/commands/prompt.d.ts +5 -0
- package/dist/commands/prompt.js +84 -0
- package/dist/commands/share.d.ts +8 -0
- package/dist/commands/share.js +50 -0
- package/dist/commands/template.d.ts +5 -0
- package/dist/commands/template.js +62 -0
- package/dist/commands/widget.d.ts +5 -0
- package/dist/commands/widget.js +164 -0
- package/dist/commands/workflow.d.ts +9 -0
- package/dist/commands/workflow.js +54 -0
- package/dist/commands/workspace.d.ts +9 -0
- package/dist/commands/workspace.js +95 -0
- package/dist/config/index.d.ts +72 -0
- package/dist/config/index.js +151 -0
- package/dist/graphql/client.d.ts +26 -0
- package/dist/graphql/client.js +274 -0
- package/dist/graphql/operations.d.ts +48 -0
- package/dist/graphql/operations.js +654 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/types/index.d.ts +30 -0
- package/dist/types/index.js +7 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/output.d.ts +62 -0
- package/dist/utils/output.js +186 -0
- package/package.json +116 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* parser commands — list, get, delete.
|
|
3
|
+
*/
|
|
4
|
+
import * as ops from '../graphql/operations.js';
|
|
5
|
+
import { execWorkspace, formatAndOutput, handleCommandError, loadTextInput } from './base.js';
|
|
6
|
+
import { printSuccess, printError, formatDate, formatStatus, truncate } from '../utils/output.js';
|
|
7
|
+
export function registerParserCommands(program) {
|
|
8
|
+
const p = program.command('parser').description('Parser operations');
|
|
9
|
+
p.command('list')
|
|
10
|
+
.description('List parsers in the current workspace (scoped to a console)')
|
|
11
|
+
.requiredOption('--console <id>', 'Console (dashboard) ID parsers belong to')
|
|
12
|
+
.option('--status <s>', 'Filter by status (active, inactive)')
|
|
13
|
+
.option('--type <t>', 'Filter by parser type (jq, jsonata, spark)')
|
|
14
|
+
.option('--input <sinkKey>', 'Filter by input sink key')
|
|
15
|
+
.option('--first <n>', 'Page size', (v) => parseInt(v, 10), 25)
|
|
16
|
+
.option('--after <cursor>', 'Cursor for next page')
|
|
17
|
+
.option('-f, --format <format>', 'Output format')
|
|
18
|
+
.action(async (o) => {
|
|
19
|
+
try {
|
|
20
|
+
// Parser resolvers are scoped per-console, not per-workspace.
|
|
21
|
+
// Canonical enum values are lowercase — match server schema exactly.
|
|
22
|
+
const VALID_STATUSES = new Set(['active', 'inactive']);
|
|
23
|
+
const VALID_TYPES = new Set(['jq', 'jsonata', 'spark']);
|
|
24
|
+
const filter = { consoleId: o.console };
|
|
25
|
+
if (o.status) {
|
|
26
|
+
const s = o.status.toLowerCase();
|
|
27
|
+
if (!VALID_STATUSES.has(s)) {
|
|
28
|
+
printError(`Invalid --status "${o.status}". Valid: ${[...VALID_STATUSES].join(', ')}`);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
filter.status = s;
|
|
32
|
+
}
|
|
33
|
+
if (o.type) {
|
|
34
|
+
const t = o.type.toLowerCase();
|
|
35
|
+
if (!VALID_TYPES.has(t)) {
|
|
36
|
+
printError(`Invalid --type "${o.type}". Valid: ${[...VALID_TYPES].join(', ')}`);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
filter.type = t;
|
|
40
|
+
}
|
|
41
|
+
if (o.input)
|
|
42
|
+
filter.inputSinkKey = o.input;
|
|
43
|
+
const d = await execWorkspace(ops.LIST_PARSERS, { first: o.first ?? 25, after: o.after, filter });
|
|
44
|
+
const items = d.listParsers.edges.map((e) => e.node);
|
|
45
|
+
formatAndOutput(o, items, {
|
|
46
|
+
headers: ['ID', 'Name', 'Type', 'Status', 'Input', 'Output', 'Updated'],
|
|
47
|
+
rows: items.map((x) => [
|
|
48
|
+
truncate(x.id, 14),
|
|
49
|
+
truncate(x.name, 24),
|
|
50
|
+
x.type,
|
|
51
|
+
formatStatus(x.status),
|
|
52
|
+
truncate(x.inputSinkKey, 18),
|
|
53
|
+
truncate(x.outputKey, 18),
|
|
54
|
+
formatDate(x.updatedAt),
|
|
55
|
+
]),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
handleCommandError(e);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
p.command('get')
|
|
63
|
+
.description('Get a parser by ID (includes the expression body)')
|
|
64
|
+
.argument('<id>')
|
|
65
|
+
.option('-f, --format <format>', 'Output format')
|
|
66
|
+
.action(async (id, o) => {
|
|
67
|
+
try {
|
|
68
|
+
const d = await execWorkspace(ops.GET_PARSER, { id });
|
|
69
|
+
if (!d.parser) {
|
|
70
|
+
printError('Parser not found');
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
formatAndOutput(o, d.parser);
|
|
74
|
+
}
|
|
75
|
+
catch (e) {
|
|
76
|
+
handleCommandError(e);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
p.command('delete')
|
|
80
|
+
.description('Delete a parser')
|
|
81
|
+
.argument('<id>')
|
|
82
|
+
.action(async (id) => {
|
|
83
|
+
try {
|
|
84
|
+
await execWorkspace(ops.DELETE_PARSER, { id });
|
|
85
|
+
printSuccess(`Deleted parser ${id}`);
|
|
86
|
+
}
|
|
87
|
+
catch (e) {
|
|
88
|
+
handleCommandError(e);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
p.command('create')
|
|
92
|
+
.description('Create a parser')
|
|
93
|
+
.requiredOption('--name <name>')
|
|
94
|
+
.requiredOption('--console <id>', 'Parent dashboard/console ID')
|
|
95
|
+
.requiredOption('--input-key <key>', 'DataSink key this parser reads from')
|
|
96
|
+
.requiredOption('--output-key <key>', 'Key for parser output (used by widgets)')
|
|
97
|
+
.requiredOption('--type <t>', 'Parser type (JQ, JSONATA, ...)')
|
|
98
|
+
.option('--expression <expr>', 'Parser expression (inline)')
|
|
99
|
+
.option('--expression-file <path>', 'Parser expression from file')
|
|
100
|
+
.option('--description <d>')
|
|
101
|
+
.option('--output-widget <id>', 'Target widget ID (v2.1)')
|
|
102
|
+
.option('--ttl <seconds>', 'Cache TTL', (v) => parseInt(v, 10))
|
|
103
|
+
.option('-f, --format <format>', 'Output format')
|
|
104
|
+
.action(async (o) => {
|
|
105
|
+
try {
|
|
106
|
+
const expression = loadTextInput(o.expressionFile, o.expression);
|
|
107
|
+
if (!expression) {
|
|
108
|
+
printError('Provide --expression or --expression-file');
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
const input = {
|
|
112
|
+
name: o.name,
|
|
113
|
+
consoleId: o.console,
|
|
114
|
+
inputSinkKey: o.inputKey,
|
|
115
|
+
outputKey: o.outputKey,
|
|
116
|
+
type: o.type.toUpperCase(),
|
|
117
|
+
expression,
|
|
118
|
+
};
|
|
119
|
+
if (o.description)
|
|
120
|
+
input.description = o.description;
|
|
121
|
+
if (o.outputWidget)
|
|
122
|
+
input.outputWidgetId = o.outputWidget;
|
|
123
|
+
if (o.ttl !== undefined)
|
|
124
|
+
input.ttl = o.ttl;
|
|
125
|
+
const d = await execWorkspace(ops.CREATE_PARSER, {
|
|
126
|
+
input,
|
|
127
|
+
});
|
|
128
|
+
printSuccess(`Created parser: ${d.createParser.name} (${d.createParser.id})`);
|
|
129
|
+
formatAndOutput(o, d.createParser);
|
|
130
|
+
}
|
|
131
|
+
catch (e) {
|
|
132
|
+
handleCommandError(e);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
p.command('update')
|
|
136
|
+
.description('Update a parser (requires current version for optimistic concurrency)')
|
|
137
|
+
.argument('<id>')
|
|
138
|
+
.requiredOption('--version <n>', 'Current parser version', (v) => parseInt(v, 10))
|
|
139
|
+
.option('--name <n>')
|
|
140
|
+
.option('--description <d>')
|
|
141
|
+
.option('--input-key <k>')
|
|
142
|
+
.option('--output-key <k>')
|
|
143
|
+
.option('--output-widget <id>')
|
|
144
|
+
.option('--status <s>', 'Parser status')
|
|
145
|
+
.option('--expression <expr>')
|
|
146
|
+
.option('--expression-file <path>')
|
|
147
|
+
.option('--ttl <seconds>', '', (v) => parseInt(v, 10))
|
|
148
|
+
.option('-f, --format <format>', 'Output format')
|
|
149
|
+
.action(async (id, o) => {
|
|
150
|
+
try {
|
|
151
|
+
const expression = loadTextInput(o.expressionFile, o.expression);
|
|
152
|
+
const input = {};
|
|
153
|
+
if (o.name)
|
|
154
|
+
input.name = o.name;
|
|
155
|
+
if (o.description !== undefined)
|
|
156
|
+
input.description = o.description;
|
|
157
|
+
if (o.inputKey)
|
|
158
|
+
input.inputSinkKey = o.inputKey;
|
|
159
|
+
if (o.outputKey)
|
|
160
|
+
input.outputKey = o.outputKey;
|
|
161
|
+
if (o.outputWidget)
|
|
162
|
+
input.outputWidgetId = o.outputWidget;
|
|
163
|
+
if (o.status)
|
|
164
|
+
input.status = o.status.toUpperCase();
|
|
165
|
+
if (expression)
|
|
166
|
+
input.expression = expression;
|
|
167
|
+
if (o.ttl !== undefined)
|
|
168
|
+
input.ttl = o.ttl;
|
|
169
|
+
const d = await execWorkspace(ops.UPDATE_PARSER, {
|
|
170
|
+
id,
|
|
171
|
+
version: o.version,
|
|
172
|
+
input,
|
|
173
|
+
});
|
|
174
|
+
printSuccess(`Updated parser ${id} (now v${d.updateParser.version})`);
|
|
175
|
+
formatAndOutput(o, d.updateParser);
|
|
176
|
+
}
|
|
177
|
+
catch (e) {
|
|
178
|
+
handleCommandError(e);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pipeline commands — list, get, delete.
|
|
3
|
+
*/
|
|
4
|
+
import * as ops from '../graphql/operations.js';
|
|
5
|
+
import { execWorkspace, formatAndOutput, handleCommandError, loadJsonInput } from './base.js';
|
|
6
|
+
import { printSuccess, printError, formatDate, formatStatus, truncate } from '../utils/output.js';
|
|
7
|
+
export function registerPipelineCommands(program) {
|
|
8
|
+
const p = program.command('pipeline').description('Pipeline operations');
|
|
9
|
+
p.command('list')
|
|
10
|
+
.description('List pipelines in the current workspace (scoped to a console)')
|
|
11
|
+
.requiredOption('--console <id>', 'Console (dashboard) ID pipelines belong to')
|
|
12
|
+
.option('--status <s>', 'Filter by status (active, draft, error, inactive)')
|
|
13
|
+
.option('--first <n>', 'Page size', (v) => parseInt(v, 10), 25)
|
|
14
|
+
.option('--after <cursor>', 'Cursor for next page')
|
|
15
|
+
.option('-f, --format <format>', 'Output format')
|
|
16
|
+
.action(async (o) => {
|
|
17
|
+
try {
|
|
18
|
+
// Canonical PipelineStatus enum values are lowercase — match schema exactly.
|
|
19
|
+
const VALID_STATUSES = new Set(['active', 'draft', 'error', 'inactive']);
|
|
20
|
+
const filter = { consoleId: o.console };
|
|
21
|
+
if (o.status) {
|
|
22
|
+
const s = o.status.toLowerCase();
|
|
23
|
+
if (!VALID_STATUSES.has(s)) {
|
|
24
|
+
printError(`Invalid --status "${o.status}". Valid: ${[...VALID_STATUSES].join(', ')}`);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
filter.status = s;
|
|
28
|
+
}
|
|
29
|
+
const d = await execWorkspace(ops.LIST_PIPELINES, { first: o.first ?? 25, after: o.after, filter });
|
|
30
|
+
const items = d.listPipelines.edges.map((e) => e.node);
|
|
31
|
+
formatAndOutput(o, items, {
|
|
32
|
+
headers: ['ID', 'Name', 'Status', 'Version', 'Last Executed', 'Updated'],
|
|
33
|
+
rows: items.map((x) => [
|
|
34
|
+
truncate(x.id, 14),
|
|
35
|
+
truncate(x.name, 28),
|
|
36
|
+
formatStatus(x.status),
|
|
37
|
+
String(x.version),
|
|
38
|
+
formatDate(x.lastExecutedAt),
|
|
39
|
+
formatDate(x.updatedAt),
|
|
40
|
+
]),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
handleCommandError(e);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
p.command('get')
|
|
48
|
+
.description('Get a pipeline by ID (includes stages)')
|
|
49
|
+
.argument('<id>')
|
|
50
|
+
.option('-f, --format <format>', 'Output format')
|
|
51
|
+
.action(async (id, o) => {
|
|
52
|
+
try {
|
|
53
|
+
const d = await execWorkspace(ops.GET_PIPELINE, { id });
|
|
54
|
+
if (!d.pipeline) {
|
|
55
|
+
printError('Pipeline not found');
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
formatAndOutput(o, d.pipeline);
|
|
59
|
+
}
|
|
60
|
+
catch (e) {
|
|
61
|
+
handleCommandError(e);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
p.command('delete')
|
|
65
|
+
.description('Delete a pipeline')
|
|
66
|
+
.argument('<id>')
|
|
67
|
+
.action(async (id) => {
|
|
68
|
+
try {
|
|
69
|
+
await execWorkspace(ops.DELETE_PIPELINE, { id });
|
|
70
|
+
printSuccess(`Deleted pipeline ${id}`);
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
handleCommandError(e);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
p.command('create')
|
|
77
|
+
.description('Create a pipeline')
|
|
78
|
+
.requiredOption('--name <name>')
|
|
79
|
+
.requiredOption('--console <id>', 'Parent dashboard/console ID')
|
|
80
|
+
.option('--description <d>')
|
|
81
|
+
.option('--status <s>', 'Initial status (DRAFT | ACTIVE | ...)')
|
|
82
|
+
.option('--stages-file <path>', 'JSON file with array of CreatePipelineStageInput')
|
|
83
|
+
.option('--stages-json <json>', 'Inline JSON array for stages')
|
|
84
|
+
.option('-f, --format <format>', 'Output format')
|
|
85
|
+
.action(async (o) => {
|
|
86
|
+
try {
|
|
87
|
+
const stages = loadJsonInput(o.stagesFile, o.stagesJson);
|
|
88
|
+
const input = {
|
|
89
|
+
name: o.name,
|
|
90
|
+
consoleId: o.console,
|
|
91
|
+
};
|
|
92
|
+
if (o.description)
|
|
93
|
+
input.description = o.description;
|
|
94
|
+
if (o.status)
|
|
95
|
+
input.status = o.status.toUpperCase();
|
|
96
|
+
if (stages)
|
|
97
|
+
input.stages = stages;
|
|
98
|
+
const d = await execWorkspace(ops.CREATE_PIPELINE, {
|
|
99
|
+
input,
|
|
100
|
+
});
|
|
101
|
+
printSuccess(`Created pipeline: ${d.createPipeline.name} (${d.createPipeline.id})`);
|
|
102
|
+
formatAndOutput(o, d.createPipeline);
|
|
103
|
+
}
|
|
104
|
+
catch (e) {
|
|
105
|
+
handleCommandError(e);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
p.command('update')
|
|
109
|
+
.description('Update a pipeline (requires current version)')
|
|
110
|
+
.argument('<id>')
|
|
111
|
+
.requiredOption('--version <n>', 'Current pipeline version', (v) => parseInt(v, 10))
|
|
112
|
+
.option('--name <n>')
|
|
113
|
+
.option('--description <d>')
|
|
114
|
+
.option('--status <s>')
|
|
115
|
+
.option('--stages-file <path>', 'JSON file with stages array to replace existing stages')
|
|
116
|
+
.option('--stages-json <json>', 'Inline JSON stages array')
|
|
117
|
+
.option('-f, --format <format>', 'Output format')
|
|
118
|
+
.action(async (id, o) => {
|
|
119
|
+
try {
|
|
120
|
+
const stages = loadJsonInput(o.stagesFile, o.stagesJson);
|
|
121
|
+
const input = {};
|
|
122
|
+
if (o.name)
|
|
123
|
+
input.name = o.name;
|
|
124
|
+
if (o.description !== undefined)
|
|
125
|
+
input.description = o.description;
|
|
126
|
+
if (o.status)
|
|
127
|
+
input.status = o.status.toUpperCase();
|
|
128
|
+
if (stages)
|
|
129
|
+
input.stages = stages;
|
|
130
|
+
const d = await execWorkspace(ops.UPDATE_PIPELINE, {
|
|
131
|
+
id,
|
|
132
|
+
version: o.version,
|
|
133
|
+
input,
|
|
134
|
+
});
|
|
135
|
+
printSuccess(`Updated pipeline ${id} (now v${d.updatePipeline.version})`);
|
|
136
|
+
formatAndOutput(o, d.updatePipeline);
|
|
137
|
+
}
|
|
138
|
+
catch (e) {
|
|
139
|
+
handleCommandError(e);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* prompt commands — AI-driven dashboard generation (generate, list, get, cancel).
|
|
3
|
+
*/
|
|
4
|
+
import * as ops from '../graphql/operations.js';
|
|
5
|
+
import { execWorkspace, formatAndOutput, handleCommandError, loadJsonInput } from './base.js';
|
|
6
|
+
import { printSuccess, printError, formatDate, formatStatus, truncate } from '../utils/output.js';
|
|
7
|
+
export function registerPromptCommands(program) {
|
|
8
|
+
const p = program.command('prompt').description('AI-driven dashboard generation');
|
|
9
|
+
p.command('generate')
|
|
10
|
+
.description('Start a new dashboard generation from a natural-language prompt')
|
|
11
|
+
.requiredOption('--prompt <text>', 'The natural-language prompt')
|
|
12
|
+
.option('--config-file <path>', 'Optional JSON with generation config')
|
|
13
|
+
.option('--config-json <json>', 'Optional inline JSON with generation config')
|
|
14
|
+
.option('-f, --format <format>', 'Output format')
|
|
15
|
+
.action(async (o) => {
|
|
16
|
+
try {
|
|
17
|
+
const extra = loadJsonInput(o.configFile, o.configJson) ?? {};
|
|
18
|
+
const input = { prompt: o.prompt, ...extra };
|
|
19
|
+
const d = await execWorkspace(ops.GENERATE_DASHBOARD_FROM_PROMPT, { input });
|
|
20
|
+
printSuccess(`Generation queued: ${d.generateDashboardFromPrompt.id}`);
|
|
21
|
+
formatAndOutput(o, d.generateDashboardFromPrompt);
|
|
22
|
+
}
|
|
23
|
+
catch (e) {
|
|
24
|
+
handleCommandError(e);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
p.command('list')
|
|
28
|
+
.description('List prompt generations')
|
|
29
|
+
.option('--status <s>', 'Filter by status')
|
|
30
|
+
.option('--first <n>', 'Page size', (v) => parseInt(v, 10), 25)
|
|
31
|
+
.option('--after <cursor>')
|
|
32
|
+
.option('-f, --format <format>', 'Output format')
|
|
33
|
+
.action(async (o) => {
|
|
34
|
+
try {
|
|
35
|
+
const d = await execWorkspace(ops.LIST_PROMPT_GENERATIONS, {
|
|
36
|
+
first: o.first ?? 25,
|
|
37
|
+
after: o.after,
|
|
38
|
+
status: o.status ? o.status.toUpperCase() : undefined,
|
|
39
|
+
});
|
|
40
|
+
const items = d.listPromptGenerations.edges.map((e) => e.node);
|
|
41
|
+
formatAndOutput(o, items, {
|
|
42
|
+
headers: ['ID', 'Status', 'Prompt', 'Created'],
|
|
43
|
+
rows: items.map((x) => [
|
|
44
|
+
truncate(x.id, 14),
|
|
45
|
+
formatStatus(x.status),
|
|
46
|
+
truncate(x.prompt, 50),
|
|
47
|
+
formatDate(x.createdAt),
|
|
48
|
+
]),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
handleCommandError(e);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
p.command('get')
|
|
56
|
+
.description('Get a prompt generation by ID')
|
|
57
|
+
.argument('<id>')
|
|
58
|
+
.option('-f, --format <format>', 'Output format')
|
|
59
|
+
.action(async (id, o) => {
|
|
60
|
+
try {
|
|
61
|
+
const d = await execWorkspace(ops.GET_PROMPT_GENERATION, { id });
|
|
62
|
+
if (!d.getPromptGeneration) {
|
|
63
|
+
printError('Prompt generation not found');
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
formatAndOutput(o, d.getPromptGeneration);
|
|
67
|
+
}
|
|
68
|
+
catch (e) {
|
|
69
|
+
handleCommandError(e);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
p.command('cancel')
|
|
73
|
+
.description('Cancel an in-flight prompt generation')
|
|
74
|
+
.argument('<id>')
|
|
75
|
+
.action(async (id) => {
|
|
76
|
+
try {
|
|
77
|
+
const d = await execWorkspace(ops.CANCEL_PROMPT_GENERATION, { id });
|
|
78
|
+
printSuccess(`Cancelled generation ${id} (status: ${d.cancelPromptGeneration.status})`);
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
handleCommandError(e);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* share commands — list dashboard shares.
|
|
3
|
+
*
|
|
4
|
+
* Create / revoke are deferred until we have a clean UX for recipient
|
|
5
|
+
* selection (user/app/link token) + expiry.
|
|
6
|
+
*/
|
|
7
|
+
import { Command } from 'commander';
|
|
8
|
+
export declare function registerShareCommands(program: Command): void;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* share commands — list dashboard shares.
|
|
3
|
+
*
|
|
4
|
+
* Create / revoke are deferred until we have a clean UX for recipient
|
|
5
|
+
* selection (user/app/link token) + expiry.
|
|
6
|
+
*/
|
|
7
|
+
import * as ops from '../graphql/operations.js';
|
|
8
|
+
import { execWorkspace, formatAndOutput, handleCommandError } from './base.js';
|
|
9
|
+
import { formatDate, truncate } from '../utils/output.js';
|
|
10
|
+
export function registerShareCommands(program) {
|
|
11
|
+
const sh = program.command('share').description('Dashboard share management');
|
|
12
|
+
sh.command('list')
|
|
13
|
+
.description('List shares for a dashboard')
|
|
14
|
+
.requiredOption('--dashboard <id>', 'Dashboard ID')
|
|
15
|
+
.option('--active <bool>', 'Filter by active status')
|
|
16
|
+
.option('--permission <p>', 'Filter by permission (VIEW, EDIT, ...)')
|
|
17
|
+
.option('--recipient-type <t>', 'USER | APP | LINK')
|
|
18
|
+
.option('--first <n>', 'Page size', (v) => parseInt(v, 10), 25)
|
|
19
|
+
.option('--after <cursor>')
|
|
20
|
+
.option('-f, --format <format>', 'Output format')
|
|
21
|
+
.action(async (o) => {
|
|
22
|
+
try {
|
|
23
|
+
const d = await execWorkspace(ops.LIST_DASHBOARD_SHARES, {
|
|
24
|
+
dashboardId: o.dashboard,
|
|
25
|
+
first: o.first ?? 25,
|
|
26
|
+
after: o.after,
|
|
27
|
+
isActive: o.active === undefined
|
|
28
|
+
? undefined
|
|
29
|
+
: o.active.toLowerCase() === 'true' || o.active === '1',
|
|
30
|
+
permission: o.permission ? o.permission.toUpperCase() : undefined,
|
|
31
|
+
recipientType: o.recipientType ? o.recipientType.toUpperCase() : undefined,
|
|
32
|
+
});
|
|
33
|
+
const items = d.listDashboardShares.edges.map((e) => e.node);
|
|
34
|
+
formatAndOutput(o, items, {
|
|
35
|
+
headers: ['ID', 'Dashboard', 'Permission', 'Active', 'Expires', 'Created'],
|
|
36
|
+
rows: items.map((x) => [
|
|
37
|
+
truncate(x.id, 14),
|
|
38
|
+
truncate(x.dashboardId, 14),
|
|
39
|
+
x.permission,
|
|
40
|
+
x.isActive ? 'yes' : 'no',
|
|
41
|
+
formatDate(x.expiresAt),
|
|
42
|
+
formatDate(x.createdAt),
|
|
43
|
+
]),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
handleCommandError(e);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* template commands — list, get dashboard templates.
|
|
3
|
+
*/
|
|
4
|
+
import * as ops from '../graphql/operations.js';
|
|
5
|
+
import { execWorkspace, formatAndOutput, handleCommandError } from './base.js';
|
|
6
|
+
import { printError, formatDate, truncate } from '../utils/output.js';
|
|
7
|
+
export function registerTemplateCommands(program) {
|
|
8
|
+
const t = program.command('template').description('Dashboard templates');
|
|
9
|
+
t.command('list')
|
|
10
|
+
.description('List dashboard templates')
|
|
11
|
+
.option('--search <term>')
|
|
12
|
+
.option('--category <c>')
|
|
13
|
+
.option('--featured', 'Only featured templates')
|
|
14
|
+
.option('--first <n>', 'Page size', (v) => parseInt(v, 10), 25)
|
|
15
|
+
.option('--after <cursor>')
|
|
16
|
+
.option('-f, --format <format>', 'Output format')
|
|
17
|
+
.action(async (o) => {
|
|
18
|
+
try {
|
|
19
|
+
const d = await execWorkspace(ops.LIST_TEMPLATES, {
|
|
20
|
+
first: o.first ?? 25,
|
|
21
|
+
after: o.after,
|
|
22
|
+
category: o.category ? o.category.toUpperCase() : undefined,
|
|
23
|
+
search: o.search,
|
|
24
|
+
isFeatured: o.featured ?? undefined,
|
|
25
|
+
});
|
|
26
|
+
const items = d.listTemplates.edges.map((e) => e.node);
|
|
27
|
+
formatAndOutput(o, items, {
|
|
28
|
+
headers: ['ID', 'Name', 'Category', 'Featured', 'Status', 'Created'],
|
|
29
|
+
rows: items.map((x) => [
|
|
30
|
+
truncate(x.id, 14),
|
|
31
|
+
truncate(x.name, 30),
|
|
32
|
+
x.category,
|
|
33
|
+
x.isFeatured ? '*' : '',
|
|
34
|
+
x.status,
|
|
35
|
+
formatDate(x.createdAt),
|
|
36
|
+
]),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
catch (e) {
|
|
40
|
+
handleCommandError(e);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
t.command('get')
|
|
44
|
+
.description('Get a template by ID')
|
|
45
|
+
.argument('<id>')
|
|
46
|
+
.option('-f, --format <format>', 'Output format')
|
|
47
|
+
.action(async (id, o) => {
|
|
48
|
+
try {
|
|
49
|
+
const d = await execWorkspace(ops.GET_TEMPLATE, {
|
|
50
|
+
id,
|
|
51
|
+
});
|
|
52
|
+
if (!d.getTemplate) {
|
|
53
|
+
printError('Template not found');
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
formatAndOutput(o, d.getTemplate);
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
handleCommandError(e);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|