faces-cli 1.0.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/LICENSE +21 -0
- package/README.md +50 -0
- package/bin/dev.js +5 -0
- package/bin/run.js +5 -0
- package/dist/base.d.ts +16 -0
- package/dist/base.js +53 -0
- package/dist/client.d.ts +36 -0
- package/dist/client.js +191 -0
- package/dist/commands/account/state.d.ts +10 -0
- package/dist/commands/account/state.js +24 -0
- package/dist/commands/auth/login.d.ts +12 -0
- package/dist/commands/auth/login.js +40 -0
- package/dist/commands/auth/logout.d.ts +10 -0
- package/dist/commands/auth/logout.js +14 -0
- package/dist/commands/auth/refresh.d.ts +10 -0
- package/dist/commands/auth/refresh.js +30 -0
- package/dist/commands/auth/register.d.ts +15 -0
- package/dist/commands/auth/register.js +45 -0
- package/dist/commands/auth/whoami.d.ts +10 -0
- package/dist/commands/auth/whoami.js +24 -0
- package/dist/commands/billing/balance.d.ts +10 -0
- package/dist/commands/billing/balance.js +24 -0
- package/dist/commands/billing/card-setup.d.ts +10 -0
- package/dist/commands/billing/card-setup.js +24 -0
- package/dist/commands/billing/checkout.d.ts +11 -0
- package/dist/commands/billing/checkout.js +30 -0
- package/dist/commands/billing/llm-costs.d.ts +11 -0
- package/dist/commands/billing/llm-costs.js +29 -0
- package/dist/commands/billing/quota.d.ts +10 -0
- package/dist/commands/billing/quota.js +24 -0
- package/dist/commands/billing/subscription.d.ts +10 -0
- package/dist/commands/billing/subscription.js +24 -0
- package/dist/commands/billing/topup.d.ts +12 -0
- package/dist/commands/billing/topup.js +33 -0
- package/dist/commands/billing/usage.d.ts +13 -0
- package/dist/commands/billing/usage.js +38 -0
- package/dist/commands/chat/chat.d.ts +20 -0
- package/dist/commands/chat/chat.js +81 -0
- package/dist/commands/chat/messages.d.ts +17 -0
- package/dist/commands/chat/messages.js +68 -0
- package/dist/commands/chat/responses.d.ts +16 -0
- package/dist/commands/chat/responses.js +67 -0
- package/dist/commands/compile/doc/create.d.ts +16 -0
- package/dist/commands/compile/doc/create.js +43 -0
- package/dist/commands/compile/doc/delete.d.ts +13 -0
- package/dist/commands/compile/doc/delete.js +28 -0
- package/dist/commands/compile/doc/get.d.ts +13 -0
- package/dist/commands/compile/doc/get.js +28 -0
- package/dist/commands/compile/doc/list.d.ts +13 -0
- package/dist/commands/compile/doc/list.js +28 -0
- package/dist/commands/compile/doc/prepare.d.ts +13 -0
- package/dist/commands/compile/doc/prepare.js +28 -0
- package/dist/commands/compile/doc/sync.d.ts +15 -0
- package/dist/commands/compile/doc/sync.js +44 -0
- package/dist/commands/compile/thread/create.d.ts +14 -0
- package/dist/commands/compile/thread/create.js +32 -0
- package/dist/commands/compile/thread/list.d.ts +13 -0
- package/dist/commands/compile/thread/list.js +28 -0
- package/dist/commands/compile/thread/message.d.ts +14 -0
- package/dist/commands/compile/thread/message.js +31 -0
- package/dist/commands/compile/thread/sync.d.ts +13 -0
- package/dist/commands/compile/thread/sync.js +28 -0
- package/dist/commands/config/clear.d.ts +12 -0
- package/dist/commands/config/clear.js +31 -0
- package/dist/commands/config/set.d.ts +14 -0
- package/dist/commands/config/set.js +19 -0
- package/dist/commands/config/show.d.ts +10 -0
- package/dist/commands/config/show.js +19 -0
- package/dist/commands/face/create.d.ts +15 -0
- package/dist/commands/face/create.js +42 -0
- package/dist/commands/face/delete.d.ts +15 -0
- package/dist/commands/face/delete.js +44 -0
- package/dist/commands/face/get.d.ts +13 -0
- package/dist/commands/face/get.js +28 -0
- package/dist/commands/face/list.d.ts +10 -0
- package/dist/commands/face/list.js +24 -0
- package/dist/commands/face/stats.d.ts +10 -0
- package/dist/commands/face/stats.js +24 -0
- package/dist/commands/face/update.d.ts +16 -0
- package/dist/commands/face/update.js +48 -0
- package/dist/commands/face/upload.d.ts +15 -0
- package/dist/commands/face/upload.js +43 -0
- package/dist/commands/keys/create.d.ts +15 -0
- package/dist/commands/keys/create.js +39 -0
- package/dist/commands/keys/list.d.ts +10 -0
- package/dist/commands/keys/list.js +24 -0
- package/dist/commands/keys/revoke.d.ts +15 -0
- package/dist/commands/keys/revoke.js +44 -0
- package/dist/commands/keys/update.d.ts +16 -0
- package/dist/commands/keys/update.js +40 -0
- package/dist/config.d.ts +16 -0
- package/dist/config.js +65 -0
- package/oclif.manifest.json +2719 -0
- package/package.json +55 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base.js';
|
|
2
|
+
export default class FaceDelete extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
6
|
+
'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
};
|
|
10
|
+
static args: {
|
|
11
|
+
face_id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
12
|
+
};
|
|
13
|
+
run(): Promise<unknown>;
|
|
14
|
+
private confirm;
|
|
15
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import { BaseCommand } from '../../base.js';
|
|
3
|
+
import { FacesAPIError } from '../../client.js';
|
|
4
|
+
import { createInterface } from 'node:readline';
|
|
5
|
+
export default class FaceDelete extends BaseCommand {
|
|
6
|
+
static description = 'Delete a face permanently';
|
|
7
|
+
static flags = {
|
|
8
|
+
...BaseCommand.baseFlags,
|
|
9
|
+
yes: Flags.boolean({ description: 'Skip confirmation', default: false }),
|
|
10
|
+
};
|
|
11
|
+
static args = {
|
|
12
|
+
face_id: Args.string({ description: 'Face ID or username', required: true }),
|
|
13
|
+
};
|
|
14
|
+
async run() {
|
|
15
|
+
const { args, flags } = await this.parse(FaceDelete);
|
|
16
|
+
const client = this.makeClient(flags);
|
|
17
|
+
if (!flags.yes) {
|
|
18
|
+
const confirmed = await this.confirm(`Delete face '${args.face_id}'? This cannot be undone.`);
|
|
19
|
+
if (!confirmed)
|
|
20
|
+
this.error('Aborted.');
|
|
21
|
+
}
|
|
22
|
+
let data;
|
|
23
|
+
try {
|
|
24
|
+
data = await client.delete(`/v1/faces/${args.face_id}`);
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
if (err instanceof FacesAPIError)
|
|
28
|
+
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
29
|
+
throw err;
|
|
30
|
+
}
|
|
31
|
+
if (!this.jsonEnabled())
|
|
32
|
+
this.printHuman(data);
|
|
33
|
+
return data;
|
|
34
|
+
}
|
|
35
|
+
confirm(message) {
|
|
36
|
+
return new Promise((resolve) => {
|
|
37
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
38
|
+
rl.question(`${message} [y/N] `, (answer) => {
|
|
39
|
+
rl.close();
|
|
40
|
+
resolve(answer.toLowerCase() === 'y');
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base.js';
|
|
2
|
+
export default class FaceGet extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
};
|
|
9
|
+
static args: {
|
|
10
|
+
face_id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
11
|
+
};
|
|
12
|
+
run(): Promise<unknown>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Args } from '@oclif/core';
|
|
2
|
+
import { BaseCommand } from '../../base.js';
|
|
3
|
+
import { FacesAPIError } from '../../client.js';
|
|
4
|
+
export default class FaceGet extends BaseCommand {
|
|
5
|
+
static description = 'Get details for a face by ID or username';
|
|
6
|
+
static flags = {
|
|
7
|
+
...BaseCommand.baseFlags,
|
|
8
|
+
};
|
|
9
|
+
static args = {
|
|
10
|
+
face_id: Args.string({ description: 'Face ID or username', required: true }),
|
|
11
|
+
};
|
|
12
|
+
async run() {
|
|
13
|
+
const { args, flags } = await this.parse(FaceGet);
|
|
14
|
+
const client = this.makeClient(flags);
|
|
15
|
+
let data;
|
|
16
|
+
try {
|
|
17
|
+
data = await client.get(`/v1/faces/${args.face_id}`);
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
if (err instanceof FacesAPIError)
|
|
21
|
+
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
22
|
+
throw err;
|
|
23
|
+
}
|
|
24
|
+
if (!this.jsonEnabled())
|
|
25
|
+
this.printHuman(data);
|
|
26
|
+
return data;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base.js';
|
|
2
|
+
export default class FaceList extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
};
|
|
9
|
+
run(): Promise<unknown>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base.js';
|
|
2
|
+
import { FacesAPIError } from '../../client.js';
|
|
3
|
+
export default class FaceList extends BaseCommand {
|
|
4
|
+
static description = 'List all owned faces';
|
|
5
|
+
static flags = {
|
|
6
|
+
...BaseCommand.baseFlags,
|
|
7
|
+
};
|
|
8
|
+
async run() {
|
|
9
|
+
const { flags } = await this.parse(FaceList);
|
|
10
|
+
const client = this.makeClient(flags);
|
|
11
|
+
let data;
|
|
12
|
+
try {
|
|
13
|
+
data = await client.get('/v1/faces');
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
if (err instanceof FacesAPIError)
|
|
17
|
+
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
18
|
+
throw err;
|
|
19
|
+
}
|
|
20
|
+
if (!this.jsonEnabled())
|
|
21
|
+
this.printHuman(data);
|
|
22
|
+
return data;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base.js';
|
|
2
|
+
export default class FaceStats extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
};
|
|
9
|
+
run(): Promise<unknown>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base.js';
|
|
2
|
+
import { FacesAPIError } from '../../client.js';
|
|
3
|
+
export default class FaceStats extends BaseCommand {
|
|
4
|
+
static description = 'Compile and chat stats for all owned faces';
|
|
5
|
+
static flags = {
|
|
6
|
+
...BaseCommand.baseFlags,
|
|
7
|
+
};
|
|
8
|
+
async run() {
|
|
9
|
+
const { flags } = await this.parse(FaceStats);
|
|
10
|
+
const client = this.makeClient(flags);
|
|
11
|
+
let data;
|
|
12
|
+
try {
|
|
13
|
+
data = await client.get('/v1/faces/stats');
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
if (err instanceof FacesAPIError)
|
|
17
|
+
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
18
|
+
throw err;
|
|
19
|
+
}
|
|
20
|
+
if (!this.jsonEnabled())
|
|
21
|
+
this.printHuman(data);
|
|
22
|
+
return data;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base.js';
|
|
2
|
+
export default class FaceUpdate extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
attr: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
tool: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
};
|
|
12
|
+
static args: {
|
|
13
|
+
face_id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
14
|
+
};
|
|
15
|
+
run(): Promise<unknown>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import { BaseCommand } from '../../base.js';
|
|
3
|
+
import { FacesAPIError } from '../../client.js';
|
|
4
|
+
export default class FaceUpdate extends BaseCommand {
|
|
5
|
+
static description = "Update a face's metadata";
|
|
6
|
+
static flags = {
|
|
7
|
+
...BaseCommand.baseFlags,
|
|
8
|
+
name: Flags.string({ description: 'New display name' }),
|
|
9
|
+
attr: Flags.string({ description: 'Update attribute KEY=VALUE (repeatable)', multiple: true }),
|
|
10
|
+
tool: Flags.string({ description: 'Tool names to set (replaces list, repeatable)', multiple: true }),
|
|
11
|
+
};
|
|
12
|
+
static args = {
|
|
13
|
+
face_id: Args.string({ description: 'Face ID or username', required: true }),
|
|
14
|
+
};
|
|
15
|
+
async run() {
|
|
16
|
+
const { args, flags } = await this.parse(FaceUpdate);
|
|
17
|
+
const client = this.makeClient(flags);
|
|
18
|
+
const payload = {};
|
|
19
|
+
if (flags.name)
|
|
20
|
+
payload.name = flags.name;
|
|
21
|
+
if (flags.attr && flags.attr.length > 0) {
|
|
22
|
+
const parsed = {};
|
|
23
|
+
for (const a of flags.attr) {
|
|
24
|
+
if (!a.includes('='))
|
|
25
|
+
this.error(`Attributes must be KEY=VALUE, got: ${a}`);
|
|
26
|
+
const idx = a.indexOf('=');
|
|
27
|
+
parsed[a.slice(0, idx).trim()] = a.slice(idx + 1).trim();
|
|
28
|
+
}
|
|
29
|
+
payload.facts = parsed;
|
|
30
|
+
}
|
|
31
|
+
if (flags.tool && flags.tool.length > 0)
|
|
32
|
+
payload.tools = flags.tool;
|
|
33
|
+
if (Object.keys(payload).length === 0)
|
|
34
|
+
this.error('Provide at least one field to update.');
|
|
35
|
+
let data;
|
|
36
|
+
try {
|
|
37
|
+
data = await client.patch(`/v1/faces/${args.face_id}`, { body: payload });
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
if (err instanceof FacesAPIError)
|
|
41
|
+
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
42
|
+
throw err;
|
|
43
|
+
}
|
|
44
|
+
if (!this.jsonEnabled())
|
|
45
|
+
this.printHuman(data);
|
|
46
|
+
return data;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base.js';
|
|
2
|
+
export default class FaceUpload extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
file: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
kind: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
};
|
|
11
|
+
static args: {
|
|
12
|
+
face_id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
13
|
+
};
|
|
14
|
+
run(): Promise<unknown>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { BaseCommand } from '../../base.js';
|
|
5
|
+
import { FacesAPIError } from '../../client.js';
|
|
6
|
+
export default class FaceUpload extends BaseCommand {
|
|
7
|
+
static description = 'Upload a file (text/PDF/audio/video) to a face';
|
|
8
|
+
static flags = {
|
|
9
|
+
...BaseCommand.baseFlags,
|
|
10
|
+
file: Flags.string({ description: 'File to upload', required: true }),
|
|
11
|
+
kind: Flags.string({
|
|
12
|
+
description: 'Upload kind: document or thread',
|
|
13
|
+
options: ['document', 'thread'],
|
|
14
|
+
default: 'document',
|
|
15
|
+
}),
|
|
16
|
+
};
|
|
17
|
+
static args = {
|
|
18
|
+
face_id: Args.string({ description: 'Face ID or username', required: true }),
|
|
19
|
+
};
|
|
20
|
+
async run() {
|
|
21
|
+
const { args, flags } = await this.parse(FaceUpload);
|
|
22
|
+
const client = this.makeClient(flags);
|
|
23
|
+
if (!fs.existsSync(flags.file))
|
|
24
|
+
this.error(`File not found: ${flags.file}`);
|
|
25
|
+
const filename = path.basename(flags.file);
|
|
26
|
+
const fileBlob = new Blob([fs.readFileSync(flags.file)], { type: 'application/octet-stream' });
|
|
27
|
+
const form = new FormData();
|
|
28
|
+
form.append('file', fileBlob, filename);
|
|
29
|
+
form.append('type', flags.kind);
|
|
30
|
+
let data;
|
|
31
|
+
try {
|
|
32
|
+
data = await client.postForm(`/v1/faces/${args.face_id}/upload`, form);
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
if (err instanceof FacesAPIError)
|
|
36
|
+
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
37
|
+
throw err;
|
|
38
|
+
}
|
|
39
|
+
if (!this.jsonEnabled())
|
|
40
|
+
this.printHuman(data);
|
|
41
|
+
return data;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base.js';
|
|
2
|
+
export default class KeysCreate extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
name: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
'expires-days': import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
budget: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
face: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
model: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
};
|
|
14
|
+
run(): Promise<unknown>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { BaseCommand } from '../../base.js';
|
|
3
|
+
import { FacesAPIError } from '../../client.js';
|
|
4
|
+
export default class KeysCreate extends BaseCommand {
|
|
5
|
+
static description = 'Create a new API key (JWT required)';
|
|
6
|
+
static flags = {
|
|
7
|
+
...BaseCommand.baseFlags,
|
|
8
|
+
name: Flags.string({ description: 'Key name/label', required: true }),
|
|
9
|
+
'expires-days': Flags.integer({ description: 'Expiry in days (omit for no expiry)' }),
|
|
10
|
+
budget: Flags.string({ description: 'Spend budget in USD' }),
|
|
11
|
+
face: Flags.string({ description: 'Allowed face username (repeatable)', multiple: true }),
|
|
12
|
+
model: Flags.string({ description: 'Allowed model name (repeatable)', multiple: true }),
|
|
13
|
+
};
|
|
14
|
+
async run() {
|
|
15
|
+
const { flags } = await this.parse(KeysCreate);
|
|
16
|
+
const client = this.makeClient(flags);
|
|
17
|
+
const payload = { name: flags.name };
|
|
18
|
+
if (flags['expires-days'] !== undefined)
|
|
19
|
+
payload.expires_days = flags['expires-days'];
|
|
20
|
+
if (flags.budget !== undefined)
|
|
21
|
+
payload.budget = Number.parseFloat(flags.budget);
|
|
22
|
+
if (flags.face && flags.face.length > 0)
|
|
23
|
+
payload.allowed_faces = flags.face;
|
|
24
|
+
if (flags.model && flags.model.length > 0)
|
|
25
|
+
payload.allowed_models = flags.model;
|
|
26
|
+
let data;
|
|
27
|
+
try {
|
|
28
|
+
data = await client.post('/v1/api-keys', { requireJwt: true, body: payload });
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
if (err instanceof FacesAPIError)
|
|
32
|
+
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
33
|
+
throw err;
|
|
34
|
+
}
|
|
35
|
+
if (!this.jsonEnabled())
|
|
36
|
+
this.printHuman(data);
|
|
37
|
+
return data;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base.js';
|
|
2
|
+
export default class KeysList extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
};
|
|
9
|
+
run(): Promise<unknown>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base.js';
|
|
2
|
+
import { FacesAPIError } from '../../client.js';
|
|
3
|
+
export default class KeysList extends BaseCommand {
|
|
4
|
+
static description = 'List all API keys (JWT required)';
|
|
5
|
+
static flags = {
|
|
6
|
+
...BaseCommand.baseFlags,
|
|
7
|
+
};
|
|
8
|
+
async run() {
|
|
9
|
+
const { flags } = await this.parse(KeysList);
|
|
10
|
+
const client = this.makeClient(flags);
|
|
11
|
+
let data;
|
|
12
|
+
try {
|
|
13
|
+
data = await client.get('/v1/api-keys', { requireJwt: true });
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
if (err instanceof FacesAPIError)
|
|
17
|
+
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
18
|
+
throw err;
|
|
19
|
+
}
|
|
20
|
+
if (!this.jsonEnabled())
|
|
21
|
+
this.printHuman(data);
|
|
22
|
+
return data;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base.js';
|
|
2
|
+
export default class KeysRevoke extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
6
|
+
'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
};
|
|
10
|
+
static args: {
|
|
11
|
+
key_id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
12
|
+
};
|
|
13
|
+
run(): Promise<unknown>;
|
|
14
|
+
private confirm;
|
|
15
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import { BaseCommand } from '../../base.js';
|
|
3
|
+
import { FacesAPIError } from '../../client.js';
|
|
4
|
+
import { createInterface } from 'node:readline';
|
|
5
|
+
export default class KeysRevoke extends BaseCommand {
|
|
6
|
+
static description = 'Revoke an API key (JWT required)';
|
|
7
|
+
static flags = {
|
|
8
|
+
...BaseCommand.baseFlags,
|
|
9
|
+
yes: Flags.boolean({ description: 'Skip confirmation', default: false }),
|
|
10
|
+
};
|
|
11
|
+
static args = {
|
|
12
|
+
key_id: Args.string({ description: 'Key ID', required: true }),
|
|
13
|
+
};
|
|
14
|
+
async run() {
|
|
15
|
+
const { args, flags } = await this.parse(KeysRevoke);
|
|
16
|
+
const client = this.makeClient(flags);
|
|
17
|
+
if (!flags.yes) {
|
|
18
|
+
const confirmed = await this.confirm(`Revoke key '${args.key_id}'?`);
|
|
19
|
+
if (!confirmed)
|
|
20
|
+
this.error('Aborted.');
|
|
21
|
+
}
|
|
22
|
+
let data;
|
|
23
|
+
try {
|
|
24
|
+
data = await client.delete(`/v1/api-keys/${args.key_id}`, { requireJwt: true });
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
if (err instanceof FacesAPIError)
|
|
28
|
+
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
29
|
+
throw err;
|
|
30
|
+
}
|
|
31
|
+
if (!this.jsonEnabled())
|
|
32
|
+
this.printHuman(data);
|
|
33
|
+
return data;
|
|
34
|
+
}
|
|
35
|
+
confirm(message) {
|
|
36
|
+
return new Promise((resolve) => {
|
|
37
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
38
|
+
rl.question(`${message} [y/N] `, (answer) => {
|
|
39
|
+
rl.close();
|
|
40
|
+
resolve(answer.toLowerCase() === 'y');
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base.js';
|
|
2
|
+
export default class KeysUpdate extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
budget: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
'reset-spent': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
};
|
|
12
|
+
static args: {
|
|
13
|
+
key_id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
14
|
+
};
|
|
15
|
+
run(): Promise<unknown>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import { BaseCommand } from '../../base.js';
|
|
3
|
+
import { FacesAPIError } from '../../client.js';
|
|
4
|
+
export default class KeysUpdate extends BaseCommand {
|
|
5
|
+
static description = 'Update API key metadata (JWT required)';
|
|
6
|
+
static flags = {
|
|
7
|
+
...BaseCommand.baseFlags,
|
|
8
|
+
name: Flags.string({ description: 'New key name' }),
|
|
9
|
+
budget: Flags.string({ description: 'New spend budget in USD' }),
|
|
10
|
+
'reset-spent': Flags.boolean({ description: 'Reset spent amount to zero', default: false }),
|
|
11
|
+
};
|
|
12
|
+
static args = {
|
|
13
|
+
key_id: Args.string({ description: 'Key ID', required: true }),
|
|
14
|
+
};
|
|
15
|
+
async run() {
|
|
16
|
+
const { args, flags } = await this.parse(KeysUpdate);
|
|
17
|
+
const client = this.makeClient(flags);
|
|
18
|
+
const payload = {};
|
|
19
|
+
if (flags.name)
|
|
20
|
+
payload.name = flags.name;
|
|
21
|
+
if (flags.budget !== undefined)
|
|
22
|
+
payload.budget = Number.parseFloat(flags.budget);
|
|
23
|
+
if (flags['reset-spent'])
|
|
24
|
+
payload.reset_spent = true;
|
|
25
|
+
if (Object.keys(payload).length === 0)
|
|
26
|
+
this.error('Provide at least one field to update.');
|
|
27
|
+
let data;
|
|
28
|
+
try {
|
|
29
|
+
data = await client.patch(`/v1/api-keys/${args.key_id}`, { requireJwt: true, body: payload });
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
if (err instanceof FacesAPIError)
|
|
33
|
+
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
34
|
+
throw err;
|
|
35
|
+
}
|
|
36
|
+
if (!this.jsonEnabled())
|
|
37
|
+
this.printHuman(data);
|
|
38
|
+
return data;
|
|
39
|
+
}
|
|
40
|
+
}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare const CONFIG_PATH: string;
|
|
2
|
+
export interface FacesConfig {
|
|
3
|
+
base_url?: string;
|
|
4
|
+
token?: string;
|
|
5
|
+
api_key?: string;
|
|
6
|
+
user_id?: string;
|
|
7
|
+
[key: string]: string | undefined;
|
|
8
|
+
}
|
|
9
|
+
export declare function loadConfig(): FacesConfig;
|
|
10
|
+
export declare function saveConfig(data: Partial<FacesConfig>): void;
|
|
11
|
+
export declare function setConfigKey(key: string, value: string): void;
|
|
12
|
+
export declare function clearConfig(): void;
|
|
13
|
+
export declare function maskedConfig(): FacesConfig;
|
|
14
|
+
export declare function resolveBaseUrl(override?: string): string;
|
|
15
|
+
export declare function resolveToken(override?: string): string | undefined;
|
|
16
|
+
export declare function resolveApiKey(override?: string): string | undefined;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
export const CONFIG_PATH = path.join(os.homedir(), '.faces', 'config.json');
|
|
5
|
+
export function loadConfig() {
|
|
6
|
+
try {
|
|
7
|
+
const raw = fs.readFileSync(CONFIG_PATH, 'utf8');
|
|
8
|
+
return JSON.parse(raw);
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return {};
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function saveConfig(data) {
|
|
15
|
+
const dir = path.dirname(CONFIG_PATH);
|
|
16
|
+
if (!fs.existsSync(dir))
|
|
17
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
18
|
+
const existing = loadConfig();
|
|
19
|
+
const merged = { ...existing, ...data };
|
|
20
|
+
fs.writeFileSync(CONFIG_PATH, JSON.stringify(merged, null, 2), { mode: 0o600 });
|
|
21
|
+
}
|
|
22
|
+
export function setConfigKey(key, value) {
|
|
23
|
+
saveConfig({ [key]: value });
|
|
24
|
+
}
|
|
25
|
+
export function clearConfig() {
|
|
26
|
+
try {
|
|
27
|
+
fs.unlinkSync(CONFIG_PATH);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// ignore missing file
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export function maskedConfig() {
|
|
34
|
+
const cfg = loadConfig();
|
|
35
|
+
const masked = { ...cfg };
|
|
36
|
+
if (masked.token)
|
|
37
|
+
masked.token = '***';
|
|
38
|
+
if (masked.api_key)
|
|
39
|
+
masked.api_key = '***';
|
|
40
|
+
return masked;
|
|
41
|
+
}
|
|
42
|
+
export function resolveBaseUrl(override) {
|
|
43
|
+
if (override)
|
|
44
|
+
return override;
|
|
45
|
+
if (process.env.FACES_BASE_URL)
|
|
46
|
+
return process.env.FACES_BASE_URL;
|
|
47
|
+
const cfg = loadConfig();
|
|
48
|
+
if (cfg.base_url)
|
|
49
|
+
return cfg.base_url;
|
|
50
|
+
return 'https://api.faces.sh';
|
|
51
|
+
}
|
|
52
|
+
export function resolveToken(override) {
|
|
53
|
+
if (override)
|
|
54
|
+
return override;
|
|
55
|
+
if (process.env.FACES_TOKEN)
|
|
56
|
+
return process.env.FACES_TOKEN;
|
|
57
|
+
return loadConfig().token;
|
|
58
|
+
}
|
|
59
|
+
export function resolveApiKey(override) {
|
|
60
|
+
if (override)
|
|
61
|
+
return override;
|
|
62
|
+
if (process.env.FACES_API_KEY)
|
|
63
|
+
return process.env.FACES_API_KEY;
|
|
64
|
+
return loadConfig().api_key;
|
|
65
|
+
}
|