@norskvideo/ctl-commands 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/commands.d.ts +404 -0
- package/commands.js +86 -0
- package/format.d.ts +3 -0
- package/format.js +131 -0
- package/index.d.ts +3 -0
- package/index.js +8 -0
- package/package.json +16 -0
- package/types.d.ts +5 -0
- package/types.js +7 -0
package/commands.d.ts
ADDED
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
import type { CertSource, HardwareProfile, NetworkMode, ProductNetworkMode, RestartPolicy } from "./types.js";
|
|
2
|
+
/** A factory function tagged with its help-display signature. */
|
|
3
|
+
export type LeafCmd<F extends (...args: never[]) => unknown> = F & {
|
|
4
|
+
readonly __sig: string;
|
|
5
|
+
};
|
|
6
|
+
export interface RelaunchOpts {
|
|
7
|
+
/** Raw `SPEC` / `SPEC@service` flag values; parsed into HostPort[] by the coercer. */
|
|
8
|
+
hostPorts?: string[];
|
|
9
|
+
}
|
|
10
|
+
export interface InstanceDeleteOpts {
|
|
11
|
+
/** Also delete the working directory — backend honours it only for a
|
|
12
|
+
* runner-created dir that clears the safety guard (see ADR 0001). */
|
|
13
|
+
purge?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface OrphanListOpts {
|
|
16
|
+
/** Omit for the human-readable table; set to dump the raw entries. */
|
|
17
|
+
output?: "yaml" | "json";
|
|
18
|
+
}
|
|
19
|
+
export interface InitOpts {
|
|
20
|
+
networkMode: NetworkMode;
|
|
21
|
+
workingDirectory?: string;
|
|
22
|
+
certPath?: string;
|
|
23
|
+
keyPath?: string;
|
|
24
|
+
certSource?: CertSource;
|
|
25
|
+
proxyUser?: string;
|
|
26
|
+
proxyPassword?: string;
|
|
27
|
+
proxyPort?: number;
|
|
28
|
+
httpRedirect?: boolean;
|
|
29
|
+
force?: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface ProxyLogsOpts {
|
|
32
|
+
type?: "access" | "error";
|
|
33
|
+
lines?: number;
|
|
34
|
+
follow?: boolean;
|
|
35
|
+
}
|
|
36
|
+
export interface SourceStartOpts {
|
|
37
|
+
port?: number;
|
|
38
|
+
}
|
|
39
|
+
export interface StatsOpts {
|
|
40
|
+
output?: "table" | "yaml" | "json";
|
|
41
|
+
}
|
|
42
|
+
export interface ShutdownOpts {
|
|
43
|
+
daemonOnly?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export interface UpgradeOpts {
|
|
46
|
+
version?: string;
|
|
47
|
+
channel?: "latest" | "stable" | "beta";
|
|
48
|
+
list?: boolean;
|
|
49
|
+
dryRun?: boolean;
|
|
50
|
+
maxVersions?: number;
|
|
51
|
+
}
|
|
52
|
+
export interface UserSetOpts {
|
|
53
|
+
password: string;
|
|
54
|
+
}
|
|
55
|
+
export interface ProductAddOpts {
|
|
56
|
+
image?: string;
|
|
57
|
+
devUrl?: string;
|
|
58
|
+
/** BYOL license file path — required unless marketplaceProvider is given. */
|
|
59
|
+
licenseFile?: string;
|
|
60
|
+
marketplaceProvider?: string;
|
|
61
|
+
}
|
|
62
|
+
export interface TemplateImportOpts {
|
|
63
|
+
name: string;
|
|
64
|
+
}
|
|
65
|
+
export interface InstanceLaunchTemplateOpts {
|
|
66
|
+
template: string;
|
|
67
|
+
param?: string[];
|
|
68
|
+
networkMode?: ProductNetworkMode;
|
|
69
|
+
/** Raw `SPEC` / `SPEC@service` flag values; parsed into HostPort[] by the coercer. */
|
|
70
|
+
hostPorts?: string[];
|
|
71
|
+
hardware?: HardwareProfile;
|
|
72
|
+
sidecars?: string[];
|
|
73
|
+
cpuPinning?: number[];
|
|
74
|
+
cpuCount?: number;
|
|
75
|
+
containerUser?: string;
|
|
76
|
+
memoryLimit?: string;
|
|
77
|
+
restartPolicy?: RestartPolicy;
|
|
78
|
+
}
|
|
79
|
+
export type GetResource = "versions" | "hardware" | "status" | "prerequisites";
|
|
80
|
+
export type Command = {
|
|
81
|
+
kind: "config.set";
|
|
82
|
+
} | {
|
|
83
|
+
kind: "config.show";
|
|
84
|
+
} | {
|
|
85
|
+
kind: "fetch.mkcert";
|
|
86
|
+
} | {
|
|
87
|
+
kind: "get";
|
|
88
|
+
resource: GetResource;
|
|
89
|
+
} | {
|
|
90
|
+
kind: "init";
|
|
91
|
+
opts: InitOpts;
|
|
92
|
+
} | {
|
|
93
|
+
kind: "inspect";
|
|
94
|
+
} | {
|
|
95
|
+
kind: "instance.delete";
|
|
96
|
+
id: string;
|
|
97
|
+
opts: InstanceDeleteOpts;
|
|
98
|
+
} | {
|
|
99
|
+
kind: "instance.describe";
|
|
100
|
+
id: string;
|
|
101
|
+
} | {
|
|
102
|
+
kind: "instance.restart";
|
|
103
|
+
id: string;
|
|
104
|
+
} | {
|
|
105
|
+
kind: "instance.stop";
|
|
106
|
+
id: string;
|
|
107
|
+
} | {
|
|
108
|
+
kind: "instance.start";
|
|
109
|
+
id: string;
|
|
110
|
+
} | {
|
|
111
|
+
kind: "instance.relaunch";
|
|
112
|
+
id: string;
|
|
113
|
+
opts: RelaunchOpts;
|
|
114
|
+
} | {
|
|
115
|
+
kind: "instance.list";
|
|
116
|
+
} | {
|
|
117
|
+
kind: "instance.exists";
|
|
118
|
+
id: string;
|
|
119
|
+
} | {
|
|
120
|
+
kind: "instance.launchTemplate";
|
|
121
|
+
id: string;
|
|
122
|
+
opts: InstanceLaunchTemplateOpts;
|
|
123
|
+
} | {
|
|
124
|
+
kind: "orphaned-dirs.list";
|
|
125
|
+
opts: OrphanListOpts;
|
|
126
|
+
} | {
|
|
127
|
+
kind: "orphaned-dirs.clear";
|
|
128
|
+
id: string;
|
|
129
|
+
} | {
|
|
130
|
+
kind: "template.list";
|
|
131
|
+
} | {
|
|
132
|
+
kind: "template.show";
|
|
133
|
+
name: string;
|
|
134
|
+
} | {
|
|
135
|
+
kind: "template.default";
|
|
136
|
+
product: string;
|
|
137
|
+
} | {
|
|
138
|
+
kind: "template.import";
|
|
139
|
+
file: string;
|
|
140
|
+
opts: TemplateImportOpts;
|
|
141
|
+
} | {
|
|
142
|
+
kind: "template.remove";
|
|
143
|
+
name: string;
|
|
144
|
+
} | {
|
|
145
|
+
kind: "product.add";
|
|
146
|
+
opts: ProductAddOpts;
|
|
147
|
+
} | {
|
|
148
|
+
kind: "product.list";
|
|
149
|
+
} | {
|
|
150
|
+
kind: "product.exists";
|
|
151
|
+
name: string;
|
|
152
|
+
} | {
|
|
153
|
+
kind: "product.remove";
|
|
154
|
+
name: string;
|
|
155
|
+
} | {
|
|
156
|
+
kind: "product.reload";
|
|
157
|
+
name: string;
|
|
158
|
+
} | {
|
|
159
|
+
kind: "product.pull";
|
|
160
|
+
name: string;
|
|
161
|
+
} | {
|
|
162
|
+
kind: "mcp";
|
|
163
|
+
} | {
|
|
164
|
+
kind: "proxy.pull";
|
|
165
|
+
} | {
|
|
166
|
+
kind: "proxy.start";
|
|
167
|
+
} | {
|
|
168
|
+
kind: "proxy.stop";
|
|
169
|
+
} | {
|
|
170
|
+
kind: "proxy.reload";
|
|
171
|
+
} | {
|
|
172
|
+
kind: "proxy.status";
|
|
173
|
+
} | {
|
|
174
|
+
kind: "proxy.logs";
|
|
175
|
+
opts: ProxyLogsOpts;
|
|
176
|
+
} | {
|
|
177
|
+
kind: "serve";
|
|
178
|
+
} | {
|
|
179
|
+
kind: "source.start";
|
|
180
|
+
instanceId: string;
|
|
181
|
+
preset: string;
|
|
182
|
+
opts: SourceStartOpts;
|
|
183
|
+
} | {
|
|
184
|
+
kind: "source.stop";
|
|
185
|
+
instanceId: string;
|
|
186
|
+
name: string;
|
|
187
|
+
} | {
|
|
188
|
+
kind: "source.list";
|
|
189
|
+
} | {
|
|
190
|
+
kind: "source.presets";
|
|
191
|
+
} | {
|
|
192
|
+
kind: "stats";
|
|
193
|
+
opts: StatsOpts;
|
|
194
|
+
} | {
|
|
195
|
+
kind: "restart";
|
|
196
|
+
} | {
|
|
197
|
+
kind: "shutdown";
|
|
198
|
+
opts: ShutdownOpts;
|
|
199
|
+
} | {
|
|
200
|
+
kind: "upgrade";
|
|
201
|
+
opts: UpgradeOpts;
|
|
202
|
+
} | {
|
|
203
|
+
kind: "user.set";
|
|
204
|
+
name: string;
|
|
205
|
+
opts: UserSetOpts;
|
|
206
|
+
} | {
|
|
207
|
+
kind: "user.delete";
|
|
208
|
+
name: string;
|
|
209
|
+
};
|
|
210
|
+
export declare const commands: {
|
|
211
|
+
readonly config: {
|
|
212
|
+
readonly set: LeafCmd<() => {
|
|
213
|
+
readonly kind: "config.set";
|
|
214
|
+
}>;
|
|
215
|
+
readonly show: LeafCmd<() => {
|
|
216
|
+
readonly kind: "config.show";
|
|
217
|
+
}>;
|
|
218
|
+
};
|
|
219
|
+
readonly fetch: {
|
|
220
|
+
readonly mkcert: LeafCmd<() => {
|
|
221
|
+
readonly kind: "fetch.mkcert";
|
|
222
|
+
}>;
|
|
223
|
+
};
|
|
224
|
+
readonly get: LeafCmd<(resource: GetResource) => {
|
|
225
|
+
readonly kind: "get";
|
|
226
|
+
readonly resource: GetResource;
|
|
227
|
+
}>;
|
|
228
|
+
readonly init: LeafCmd<(opts: InitOpts) => {
|
|
229
|
+
readonly kind: "init";
|
|
230
|
+
readonly opts: InitOpts;
|
|
231
|
+
}>;
|
|
232
|
+
readonly inspect: LeafCmd<() => {
|
|
233
|
+
readonly kind: "inspect";
|
|
234
|
+
}>;
|
|
235
|
+
readonly instance: {
|
|
236
|
+
readonly delete: LeafCmd<(id: string, opts?: InstanceDeleteOpts) => {
|
|
237
|
+
readonly kind: "instance.delete";
|
|
238
|
+
readonly id: string;
|
|
239
|
+
readonly opts: InstanceDeleteOpts;
|
|
240
|
+
}>;
|
|
241
|
+
readonly describe: LeafCmd<(id: string) => {
|
|
242
|
+
readonly kind: "instance.describe";
|
|
243
|
+
readonly id: string;
|
|
244
|
+
}>;
|
|
245
|
+
readonly restart: LeafCmd<(id: string) => {
|
|
246
|
+
readonly kind: "instance.restart";
|
|
247
|
+
readonly id: string;
|
|
248
|
+
}>;
|
|
249
|
+
readonly stop: LeafCmd<(id: string) => {
|
|
250
|
+
readonly kind: "instance.stop";
|
|
251
|
+
readonly id: string;
|
|
252
|
+
}>;
|
|
253
|
+
readonly start: LeafCmd<(id: string) => {
|
|
254
|
+
readonly kind: "instance.start";
|
|
255
|
+
readonly id: string;
|
|
256
|
+
}>;
|
|
257
|
+
readonly relaunch: LeafCmd<(id: string, opts?: RelaunchOpts) => {
|
|
258
|
+
readonly kind: "instance.relaunch";
|
|
259
|
+
readonly id: string;
|
|
260
|
+
readonly opts: RelaunchOpts;
|
|
261
|
+
}>;
|
|
262
|
+
readonly list: LeafCmd<() => {
|
|
263
|
+
readonly kind: "instance.list";
|
|
264
|
+
}>;
|
|
265
|
+
readonly exists: LeafCmd<(id: string) => {
|
|
266
|
+
readonly kind: "instance.exists";
|
|
267
|
+
readonly id: string;
|
|
268
|
+
}>;
|
|
269
|
+
readonly launchTemplate: LeafCmd<(id: string, opts: InstanceLaunchTemplateOpts) => {
|
|
270
|
+
readonly kind: "instance.launchTemplate";
|
|
271
|
+
readonly id: string;
|
|
272
|
+
readonly opts: InstanceLaunchTemplateOpts;
|
|
273
|
+
}>;
|
|
274
|
+
};
|
|
275
|
+
readonly orphanedDirs: {
|
|
276
|
+
readonly list: LeafCmd<(opts?: OrphanListOpts) => {
|
|
277
|
+
readonly kind: "orphaned-dirs.list";
|
|
278
|
+
readonly opts: OrphanListOpts;
|
|
279
|
+
}>;
|
|
280
|
+
readonly clear: LeafCmd<(id: string) => {
|
|
281
|
+
readonly kind: "orphaned-dirs.clear";
|
|
282
|
+
readonly id: string;
|
|
283
|
+
}>;
|
|
284
|
+
};
|
|
285
|
+
readonly product: {
|
|
286
|
+
readonly add: LeafCmd<(opts?: ProductAddOpts) => {
|
|
287
|
+
readonly kind: "product.add";
|
|
288
|
+
readonly opts: ProductAddOpts;
|
|
289
|
+
}>;
|
|
290
|
+
readonly list: LeafCmd<() => {
|
|
291
|
+
readonly kind: "product.list";
|
|
292
|
+
}>;
|
|
293
|
+
readonly exists: LeafCmd<(name: string) => {
|
|
294
|
+
readonly kind: "product.exists";
|
|
295
|
+
readonly name: string;
|
|
296
|
+
}>;
|
|
297
|
+
readonly remove: LeafCmd<(name: string) => {
|
|
298
|
+
readonly kind: "product.remove";
|
|
299
|
+
readonly name: string;
|
|
300
|
+
}>;
|
|
301
|
+
readonly reload: LeafCmd<(name: string) => {
|
|
302
|
+
readonly kind: "product.reload";
|
|
303
|
+
readonly name: string;
|
|
304
|
+
}>;
|
|
305
|
+
readonly pull: LeafCmd<(name: string) => {
|
|
306
|
+
readonly kind: "product.pull";
|
|
307
|
+
readonly name: string;
|
|
308
|
+
}>;
|
|
309
|
+
};
|
|
310
|
+
readonly template: {
|
|
311
|
+
readonly list: LeafCmd<() => {
|
|
312
|
+
readonly kind: "template.list";
|
|
313
|
+
}>;
|
|
314
|
+
readonly show: LeafCmd<(name: string) => {
|
|
315
|
+
readonly kind: "template.show";
|
|
316
|
+
readonly name: string;
|
|
317
|
+
}>;
|
|
318
|
+
readonly default: LeafCmd<(product: string) => {
|
|
319
|
+
readonly kind: "template.default";
|
|
320
|
+
readonly product: string;
|
|
321
|
+
}>;
|
|
322
|
+
readonly import: LeafCmd<(file: string, opts: TemplateImportOpts) => {
|
|
323
|
+
readonly kind: "template.import";
|
|
324
|
+
readonly file: string;
|
|
325
|
+
readonly opts: TemplateImportOpts;
|
|
326
|
+
}>;
|
|
327
|
+
readonly remove: LeafCmd<(name: string) => {
|
|
328
|
+
readonly kind: "template.remove";
|
|
329
|
+
readonly name: string;
|
|
330
|
+
}>;
|
|
331
|
+
};
|
|
332
|
+
readonly proxy: {
|
|
333
|
+
readonly pull: LeafCmd<() => {
|
|
334
|
+
readonly kind: "proxy.pull";
|
|
335
|
+
}>;
|
|
336
|
+
readonly start: LeafCmd<() => {
|
|
337
|
+
readonly kind: "proxy.start";
|
|
338
|
+
}>;
|
|
339
|
+
readonly stop: LeafCmd<() => {
|
|
340
|
+
readonly kind: "proxy.stop";
|
|
341
|
+
}>;
|
|
342
|
+
readonly reload: LeafCmd<() => {
|
|
343
|
+
readonly kind: "proxy.reload";
|
|
344
|
+
}>;
|
|
345
|
+
readonly status: LeafCmd<() => {
|
|
346
|
+
readonly kind: "proxy.status";
|
|
347
|
+
}>;
|
|
348
|
+
readonly logs: LeafCmd<(opts?: ProxyLogsOpts) => {
|
|
349
|
+
readonly kind: "proxy.logs";
|
|
350
|
+
readonly opts: ProxyLogsOpts;
|
|
351
|
+
}>;
|
|
352
|
+
};
|
|
353
|
+
readonly mcp: LeafCmd<() => {
|
|
354
|
+
readonly kind: "mcp";
|
|
355
|
+
}>;
|
|
356
|
+
readonly serve: LeafCmd<() => {
|
|
357
|
+
readonly kind: "serve";
|
|
358
|
+
}>;
|
|
359
|
+
readonly source: {
|
|
360
|
+
readonly start: LeafCmd<(instanceId: string, preset: string, opts?: SourceStartOpts) => {
|
|
361
|
+
readonly kind: "source.start";
|
|
362
|
+
readonly instanceId: string;
|
|
363
|
+
readonly preset: string;
|
|
364
|
+
readonly opts: SourceStartOpts;
|
|
365
|
+
}>;
|
|
366
|
+
readonly stop: LeafCmd<(instanceId: string, name: string) => {
|
|
367
|
+
readonly kind: "source.stop";
|
|
368
|
+
readonly instanceId: string;
|
|
369
|
+
readonly name: string;
|
|
370
|
+
}>;
|
|
371
|
+
readonly list: LeafCmd<() => {
|
|
372
|
+
readonly kind: "source.list";
|
|
373
|
+
}>;
|
|
374
|
+
readonly presets: LeafCmd<() => {
|
|
375
|
+
readonly kind: "source.presets";
|
|
376
|
+
}>;
|
|
377
|
+
};
|
|
378
|
+
readonly stats: LeafCmd<(opts?: StatsOpts) => {
|
|
379
|
+
readonly kind: "stats";
|
|
380
|
+
readonly opts: StatsOpts;
|
|
381
|
+
}>;
|
|
382
|
+
readonly restart: LeafCmd<() => {
|
|
383
|
+
readonly kind: "restart";
|
|
384
|
+
}>;
|
|
385
|
+
readonly shutdown: LeafCmd<(opts?: ShutdownOpts) => {
|
|
386
|
+
readonly kind: "shutdown";
|
|
387
|
+
readonly opts: ShutdownOpts;
|
|
388
|
+
}>;
|
|
389
|
+
readonly upgrade: LeafCmd<(opts?: UpgradeOpts) => {
|
|
390
|
+
readonly kind: "upgrade";
|
|
391
|
+
readonly opts: UpgradeOpts;
|
|
392
|
+
}>;
|
|
393
|
+
readonly user: {
|
|
394
|
+
readonly set: LeafCmd<(name: string, opts: UserSetOpts) => {
|
|
395
|
+
readonly kind: "user.set";
|
|
396
|
+
readonly name: string;
|
|
397
|
+
readonly opts: UserSetOpts;
|
|
398
|
+
}>;
|
|
399
|
+
readonly delete: LeafCmd<(name: string) => {
|
|
400
|
+
readonly kind: "user.delete";
|
|
401
|
+
readonly name: string;
|
|
402
|
+
}>;
|
|
403
|
+
};
|
|
404
|
+
};
|
package/commands.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// Typed CLI command factory. Mirrors the yargs hierarchy in cli-builder.ts so
|
|
2
|
+
// callers (mostly tests) can express commands with full type checking instead
|
|
3
|
+
// of stringly-typed argv arrays. Renaming or removing a CLI verb is a
|
|
4
|
+
// typecheck error at the call site, not a runtime "Unknown arguments" surprise.
|
|
5
|
+
//
|
|
6
|
+
// Each leaf factory carries a `__sig` field with the help-display signature
|
|
7
|
+
// (e.g. "launch <id>"). `describeCommands` (in ./help.ts) reads these to build
|
|
8
|
+
// HelpTrees, and the `DescriptionsFor<T>` type forces every per-module
|
|
9
|
+
// description object to enumerate exactly the leaves of its factory subtree —
|
|
10
|
+
// drift between this file and commands/<group>.ts is a typecheck error.
|
|
11
|
+
//
|
|
12
|
+
// Pair with `format.toArgv(cmd)` to render to a string[] for execution and
|
|
13
|
+
// `format.commandToString(cmd)` for human-readable error messages.
|
|
14
|
+
function leaf(sig, fn) {
|
|
15
|
+
return Object.assign(fn, { __sig: sig });
|
|
16
|
+
}
|
|
17
|
+
// ---- Factory tree -----------------------------------------------------------
|
|
18
|
+
// Mirrors cli-builder.ts. Adding a new CLI verb requires a Command variant
|
|
19
|
+
// here, a leaf entry below, and (via DescriptionsFor) a description in the
|
|
20
|
+
// owning command module's helpEntries.
|
|
21
|
+
export const commands = {
|
|
22
|
+
config: {
|
|
23
|
+
set: leaf("set", () => ({ kind: "config.set" })),
|
|
24
|
+
show: leaf("show", () => ({ kind: "config.show" })),
|
|
25
|
+
},
|
|
26
|
+
fetch: {
|
|
27
|
+
mkcert: leaf("mkcert", () => ({ kind: "fetch.mkcert" })),
|
|
28
|
+
},
|
|
29
|
+
get: leaf("get <resource>", (resource) => ({ kind: "get", resource })),
|
|
30
|
+
init: leaf("init", (opts) => ({ kind: "init", opts })),
|
|
31
|
+
inspect: leaf("inspect", () => ({ kind: "inspect" })),
|
|
32
|
+
instance: {
|
|
33
|
+
delete: leaf("delete <id>", (id, opts = {}) => ({ kind: "instance.delete", id, opts })),
|
|
34
|
+
describe: leaf("describe <id>", (id) => ({ kind: "instance.describe", id })),
|
|
35
|
+
restart: leaf("restart <id>", (id) => ({ kind: "instance.restart", id })),
|
|
36
|
+
stop: leaf("stop <id>", (id) => ({ kind: "instance.stop", id })),
|
|
37
|
+
start: leaf("start <id>", (id) => ({ kind: "instance.start", id })),
|
|
38
|
+
relaunch: leaf("relaunch <id>", (id, opts = {}) => ({ kind: "instance.relaunch", id, opts })),
|
|
39
|
+
list: leaf("list", () => ({ kind: "instance.list" })),
|
|
40
|
+
exists: leaf("exists <id>", (id) => ({ kind: "instance.exists", id })),
|
|
41
|
+
launchTemplate: leaf("launch-template <id>", (id, opts) => ({ kind: "instance.launchTemplate", id, opts })),
|
|
42
|
+
},
|
|
43
|
+
orphanedDirs: {
|
|
44
|
+
list: leaf("list", (opts = {}) => ({ kind: "orphaned-dirs.list", opts })),
|
|
45
|
+
clear: leaf("clear <id>", (id) => ({ kind: "orphaned-dirs.clear", id })),
|
|
46
|
+
},
|
|
47
|
+
product: {
|
|
48
|
+
add: leaf("add", (opts = {}) => ({ kind: "product.add", opts })),
|
|
49
|
+
list: leaf("list", () => ({ kind: "product.list" })),
|
|
50
|
+
exists: leaf("exists <name>", (name) => ({ kind: "product.exists", name })),
|
|
51
|
+
remove: leaf("remove <name>", (name) => ({ kind: "product.remove", name })),
|
|
52
|
+
reload: leaf("reload <name>", (name) => ({ kind: "product.reload", name })),
|
|
53
|
+
pull: leaf("pull <name>", (name) => ({ kind: "product.pull", name })),
|
|
54
|
+
},
|
|
55
|
+
template: {
|
|
56
|
+
list: leaf("list", () => ({ kind: "template.list" })),
|
|
57
|
+
show: leaf("show <name>", (name) => ({ kind: "template.show", name })),
|
|
58
|
+
default: leaf("default <product>", (product) => ({ kind: "template.default", product })),
|
|
59
|
+
import: leaf("import <file>", (file, opts) => ({ kind: "template.import", file, opts })),
|
|
60
|
+
remove: leaf("remove <name>", (name) => ({ kind: "template.remove", name })),
|
|
61
|
+
},
|
|
62
|
+
proxy: {
|
|
63
|
+
pull: leaf("pull", () => ({ kind: "proxy.pull" })),
|
|
64
|
+
start: leaf("start", () => ({ kind: "proxy.start" })),
|
|
65
|
+
stop: leaf("stop", () => ({ kind: "proxy.stop" })),
|
|
66
|
+
reload: leaf("reload", () => ({ kind: "proxy.reload" })),
|
|
67
|
+
status: leaf("status", () => ({ kind: "proxy.status" })),
|
|
68
|
+
logs: leaf("logs", (opts = {}) => ({ kind: "proxy.logs", opts })),
|
|
69
|
+
},
|
|
70
|
+
mcp: leaf("mcp", () => ({ kind: "mcp" })),
|
|
71
|
+
serve: leaf("serve", () => ({ kind: "serve" })),
|
|
72
|
+
source: {
|
|
73
|
+
start: leaf("start <instanceId> <preset>", (instanceId, preset, opts = {}) => ({ kind: "source.start", instanceId, preset, opts })),
|
|
74
|
+
stop: leaf("stop <instanceId> <name>", (instanceId, name) => ({ kind: "source.stop", instanceId, name })),
|
|
75
|
+
list: leaf("list", () => ({ kind: "source.list" })),
|
|
76
|
+
presets: leaf("presets", () => ({ kind: "source.presets" })),
|
|
77
|
+
},
|
|
78
|
+
stats: leaf("stats", (opts = {}) => ({ kind: "stats", opts })),
|
|
79
|
+
restart: leaf("restart", () => ({ kind: "restart" })),
|
|
80
|
+
shutdown: leaf("shutdown", (opts = {}) => ({ kind: "shutdown", opts })),
|
|
81
|
+
upgrade: leaf("upgrade", (opts = {}) => ({ kind: "upgrade", opts })),
|
|
82
|
+
user: {
|
|
83
|
+
set: leaf("set <name>", (name, opts) => ({ kind: "user.set", name, opts })),
|
|
84
|
+
delete: leaf("delete <name>", (name) => ({ kind: "user.delete", name })),
|
|
85
|
+
},
|
|
86
|
+
};
|
package/format.d.ts
ADDED
package/format.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// Pretty-printer for typed Commands. Render to either an argv string[] (for
|
|
2
|
+
// spawning the CLI) or a single human-readable string (for error messages and
|
|
3
|
+
// docs). Mirrors the CLI's flag conventions: camelCase option keys become
|
|
4
|
+
// --kebab-case flags; arrays become repeated --flag value pairs; boolean true
|
|
5
|
+
// becomes a bare --flag, boolean false is omitted (yargs default).
|
|
6
|
+
const camelToKebab = (s) => s.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
|
7
|
+
/** Self-referential constraint: every key in T must map to an OptValue. Lets
|
|
8
|
+
* callers pass typed interfaces (LaunchOpts, InitOpts, …) without polluting
|
|
9
|
+
* them with index signatures, while still rejecting an opts object that
|
|
10
|
+
* carries an unsupported field shape (e.g. a Date or nested object). */
|
|
11
|
+
function formatOpts(opts) {
|
|
12
|
+
if (!opts)
|
|
13
|
+
return [];
|
|
14
|
+
const out = [];
|
|
15
|
+
for (const [key, val] of Object.entries(opts)) {
|
|
16
|
+
if (val === undefined)
|
|
17
|
+
continue;
|
|
18
|
+
const flag = `--${camelToKebab(key)}`;
|
|
19
|
+
if (typeof val === "boolean") {
|
|
20
|
+
if (val)
|
|
21
|
+
out.push(flag);
|
|
22
|
+
}
|
|
23
|
+
else if (Array.isArray(val)) {
|
|
24
|
+
for (const v of val)
|
|
25
|
+
out.push(flag, String(v));
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
out.push(flag, String(val));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
export function toArgv(cmd) {
|
|
34
|
+
switch (cmd.kind) {
|
|
35
|
+
case "config.set":
|
|
36
|
+
return ["config", "set"];
|
|
37
|
+
case "config.show":
|
|
38
|
+
return ["config", "show"];
|
|
39
|
+
case "fetch.mkcert":
|
|
40
|
+
return ["fetch", "mkcert"];
|
|
41
|
+
case "get":
|
|
42
|
+
return ["get", cmd.resource];
|
|
43
|
+
case "init":
|
|
44
|
+
return ["init", ...formatOpts(cmd.opts)];
|
|
45
|
+
case "inspect":
|
|
46
|
+
return ["inspect"];
|
|
47
|
+
case "instance.delete":
|
|
48
|
+
return ["instance", "delete", cmd.id, ...formatOpts(cmd.opts)];
|
|
49
|
+
case "instance.describe":
|
|
50
|
+
return ["instance", "describe", cmd.id];
|
|
51
|
+
case "instance.restart":
|
|
52
|
+
return ["instance", "restart", cmd.id];
|
|
53
|
+
case "instance.stop":
|
|
54
|
+
return ["instance", "stop", cmd.id];
|
|
55
|
+
case "instance.start":
|
|
56
|
+
return ["instance", "start", cmd.id];
|
|
57
|
+
case "instance.relaunch":
|
|
58
|
+
return ["instance", "relaunch", cmd.id, ...formatOpts(cmd.opts)];
|
|
59
|
+
case "instance.list":
|
|
60
|
+
return ["instance", "list"];
|
|
61
|
+
case "instance.exists":
|
|
62
|
+
return ["instance", "exists", cmd.id];
|
|
63
|
+
case "instance.launchTemplate":
|
|
64
|
+
return ["instance", "launch-template", cmd.id, ...formatOpts(cmd.opts)];
|
|
65
|
+
case "orphaned-dirs.list":
|
|
66
|
+
return ["orphaned-dirs", "list", ...formatOpts(cmd.opts)];
|
|
67
|
+
case "orphaned-dirs.clear":
|
|
68
|
+
return ["orphaned-dirs", "clear", cmd.id];
|
|
69
|
+
case "product.add":
|
|
70
|
+
return ["product", "add", ...formatOpts(cmd.opts)];
|
|
71
|
+
case "product.list":
|
|
72
|
+
return ["product", "list"];
|
|
73
|
+
case "product.exists":
|
|
74
|
+
return ["product", "exists", cmd.name];
|
|
75
|
+
case "product.remove":
|
|
76
|
+
return ["product", "remove", cmd.name];
|
|
77
|
+
case "product.reload":
|
|
78
|
+
return ["product", "reload", cmd.name];
|
|
79
|
+
case "product.pull":
|
|
80
|
+
return ["product", "pull", cmd.name];
|
|
81
|
+
case "template.list":
|
|
82
|
+
return ["template", "list"];
|
|
83
|
+
case "template.show":
|
|
84
|
+
return ["template", "show", cmd.name];
|
|
85
|
+
case "template.default":
|
|
86
|
+
return ["template", "default", cmd.product];
|
|
87
|
+
case "template.import":
|
|
88
|
+
return ["template", "import", cmd.file, ...formatOpts(cmd.opts)];
|
|
89
|
+
case "template.remove":
|
|
90
|
+
return ["template", "remove", cmd.name];
|
|
91
|
+
case "mcp":
|
|
92
|
+
return ["mcp"];
|
|
93
|
+
case "proxy.pull":
|
|
94
|
+
return ["proxy", "pull"];
|
|
95
|
+
case "proxy.start":
|
|
96
|
+
return ["proxy", "start"];
|
|
97
|
+
case "proxy.stop":
|
|
98
|
+
return ["proxy", "stop"];
|
|
99
|
+
case "proxy.reload":
|
|
100
|
+
return ["proxy", "reload"];
|
|
101
|
+
case "proxy.status":
|
|
102
|
+
return ["proxy", "status"];
|
|
103
|
+
case "proxy.logs":
|
|
104
|
+
return ["proxy", "logs", ...formatOpts(cmd.opts)];
|
|
105
|
+
case "serve":
|
|
106
|
+
return ["serve"];
|
|
107
|
+
case "source.start":
|
|
108
|
+
return ["source", "start", cmd.instanceId, cmd.preset, ...formatOpts(cmd.opts)];
|
|
109
|
+
case "source.stop":
|
|
110
|
+
return ["source", "stop", cmd.instanceId, cmd.name];
|
|
111
|
+
case "source.list":
|
|
112
|
+
return ["source", "list"];
|
|
113
|
+
case "source.presets":
|
|
114
|
+
return ["source", "presets"];
|
|
115
|
+
case "stats":
|
|
116
|
+
return ["stats", ...formatOpts(cmd.opts)];
|
|
117
|
+
case "restart":
|
|
118
|
+
return ["restart"];
|
|
119
|
+
case "shutdown":
|
|
120
|
+
return ["shutdown", ...formatOpts(cmd.opts)];
|
|
121
|
+
case "upgrade":
|
|
122
|
+
return ["upgrade", ...formatOpts(cmd.opts)];
|
|
123
|
+
case "user.set":
|
|
124
|
+
return ["user", "set", cmd.name, ...formatOpts(cmd.opts)];
|
|
125
|
+
case "user.delete":
|
|
126
|
+
return ["user", "delete", cmd.name];
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
export function commandToString(cmd) {
|
|
130
|
+
return ["norsk-ctl", ...toArgv(cmd)].join(" ");
|
|
131
|
+
}
|
package/index.d.ts
ADDED
package/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Typed command surface for driving the norsk-ctl CLI. `commands` builds typed
|
|
2
|
+
// Command values, `toArgv`/`commandToString` render them for spawning and for
|
|
3
|
+
// error messages. Consumed by norsk-ctl's own CLI modules and by product test
|
|
4
|
+
// harnesses, which pin it via a published range so a split-repo product keeps a
|
|
5
|
+
// typed launch surface without reaching into norsk-ctl's source.
|
|
6
|
+
export * from "./commands.js";
|
|
7
|
+
export * from "./format.js";
|
|
8
|
+
export * from "./types.js";
|
package/package.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@norskvideo/ctl-commands",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": {
|
|
7
|
+
"types": "./index.d.ts",
|
|
8
|
+
"default": "./index.js"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"main": "./index.js",
|
|
12
|
+
"types": "./index.d.ts",
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public"
|
|
15
|
+
}
|
|
16
|
+
}
|
package/types.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type NetworkMode = "docker" | "hybrid";
|
|
2
|
+
export type CertSource = "mkcert" | "self-signed" | "user" | "certbot";
|
|
3
|
+
export type HardwareProfile = "none" | "nvidia" | "quadra";
|
|
4
|
+
export type ProductNetworkMode = "docker" | "hybrid";
|
|
5
|
+
export type RestartPolicy = "unless-stopped" | "always" | "on-failure" | "no";
|
package/types.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// The ctl CLI's launch/config option vocabulary. These closed unions mirror the
|
|
2
|
+
// zod enums in norsk-ctl's API spec (shared/src/spec/schemas). They are copied
|
|
3
|
+
// rather than imported because this package publishes standalone — it cannot
|
|
4
|
+
// depend on norsk-ctl's private spec. norsk-ctl carries a drift-guard test
|
|
5
|
+
// (commands-vocab.guard.test.ts) that fails typecheck/CI the moment a union
|
|
6
|
+
// here diverges from the spec it shadows.
|
|
7
|
+
export {};
|