faces-cli 1.5.14 → 1.6.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/client.d.ts +14 -1
- package/dist/client.js +40 -6
- package/dist/commands/account/preferences.d.ts +15 -0
- package/dist/commands/account/preferences.js +65 -0
- package/dist/commands/catalog/backup.d.ts +10 -0
- package/dist/commands/catalog/backup.js +101 -0
- package/dist/commands/catalog/restore.d.ts +16 -0
- package/dist/commands/catalog/restore.js +147 -0
- package/dist/commands/chat/chat.d.ts +2 -0
- package/dist/commands/chat/chat.js +88 -18
- package/dist/commands/chat/messages.d.ts +1 -0
- package/dist/commands/chat/messages.js +25 -6
- package/dist/commands/chat/responses.d.ts +1 -0
- package/dist/commands/chat/responses.js +25 -6
- package/dist/commands/compile/all.d.ts +11 -0
- package/dist/commands/compile/all.js +116 -0
- package/dist/commands/compile/thread/create.d.ts +1 -0
- package/dist/commands/compile/thread/create.js +11 -1
- package/dist/commands/compile/thread/message.d.ts +1 -0
- package/dist/commands/compile/thread/message.js +13 -2
- package/oclif.manifest.json +987 -712
- package/package.json +1 -1
|
@@ -9,6 +9,7 @@ export default class ChatMessages extends BaseCommand {
|
|
|
9
9
|
system: Flags.string({ description: 'System prompt' }),
|
|
10
10
|
stream: Flags.boolean({ description: 'Stream the response', default: false }),
|
|
11
11
|
'max-tokens': Flags.integer({ description: 'Max tokens', default: 1024 }),
|
|
12
|
+
'oauth-only': Flags.boolean({ description: 'Prevent fallback to paid system key (use OAuth only)', default: false }),
|
|
12
13
|
};
|
|
13
14
|
static args = {
|
|
14
15
|
face_model: Args.string({ description: 'Face model (e.g. myface or myface@claude-sonnet-4-6)', required: true }),
|
|
@@ -25,6 +26,8 @@ export default class ChatMessages extends BaseCommand {
|
|
|
25
26
|
};
|
|
26
27
|
if (flags.system)
|
|
27
28
|
payload.system = flags.system;
|
|
29
|
+
if (flags['oauth-only'])
|
|
30
|
+
payload.oauth_only = true;
|
|
28
31
|
try {
|
|
29
32
|
if (flags.stream) {
|
|
30
33
|
for await (const line of client.stream('/v1/messages', payload)) {
|
|
@@ -48,20 +51,36 @@ export default class ChatMessages extends BaseCommand {
|
|
|
48
51
|
process.stdout.write('\n');
|
|
49
52
|
return {};
|
|
50
53
|
}
|
|
51
|
-
const data =
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
const { data, headers } = await client.postWithHeaders('/v1/messages', { body: payload });
|
|
55
|
+
const body = data;
|
|
56
|
+
if (this.jsonEnabled()) {
|
|
57
|
+
const meta = {};
|
|
58
|
+
if (headers['x-faces-provider'])
|
|
59
|
+
meta.provider = headers['x-faces-provider'];
|
|
60
|
+
if (headers['x-faces-cost-usd'])
|
|
61
|
+
meta.cost_usd = headers['x-faces-cost-usd'];
|
|
62
|
+
if (Object.keys(meta).length > 0)
|
|
63
|
+
body._meta = meta;
|
|
64
|
+
return body;
|
|
65
|
+
}
|
|
54
66
|
let content = '';
|
|
55
|
-
for (const block of
|
|
67
|
+
for (const block of body.content ?? []) {
|
|
56
68
|
if (block.type === 'text')
|
|
57
69
|
content += String(block.text ?? '');
|
|
58
70
|
}
|
|
59
71
|
this.log(content);
|
|
60
|
-
return
|
|
72
|
+
return body;
|
|
61
73
|
}
|
|
62
74
|
catch (err) {
|
|
63
|
-
if (err instanceof FacesAPIError)
|
|
75
|
+
if (err instanceof FacesAPIError) {
|
|
76
|
+
if (err.errorCode === 'oauth_rejected') {
|
|
77
|
+
const hint = err.fallbackAvailable
|
|
78
|
+
? 'Run `faces account:preferences api_fallback true` to allow paid fallback.'
|
|
79
|
+
: 'Run `faces billing:topup` to add credits, then enable fallback with `faces account:preferences api_fallback true`.';
|
|
80
|
+
this.error(`OAuth failed: ${err.message}\n${hint}`);
|
|
81
|
+
}
|
|
64
82
|
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
83
|
+
}
|
|
65
84
|
throw err;
|
|
66
85
|
}
|
|
67
86
|
}
|
|
@@ -5,6 +5,7 @@ export default class ChatResponses extends BaseCommand {
|
|
|
5
5
|
message: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
6
|
instructions: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
7
|
stream: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
'oauth-only': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
9
|
'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
10
|
token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
11
|
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -8,6 +8,7 @@ export default class ChatResponses extends BaseCommand {
|
|
|
8
8
|
message: Flags.string({ char: 'm', description: 'User input message', required: true }),
|
|
9
9
|
instructions: Flags.string({ description: 'System instructions' }),
|
|
10
10
|
stream: Flags.boolean({ description: 'Stream the response', default: false }),
|
|
11
|
+
'oauth-only': Flags.boolean({ description: 'Prevent fallback to paid system key (use OAuth only)', default: false }),
|
|
11
12
|
};
|
|
12
13
|
static args = {
|
|
13
14
|
face_model: Args.string({ description: 'Face model (e.g. myface or myface@gpt-4o)', required: true }),
|
|
@@ -22,6 +23,8 @@ export default class ChatResponses extends BaseCommand {
|
|
|
22
23
|
};
|
|
23
24
|
if (flags.instructions)
|
|
24
25
|
payload.instructions = flags.instructions;
|
|
26
|
+
if (flags['oauth-only'])
|
|
27
|
+
payload.oauth_only = true;
|
|
25
28
|
try {
|
|
26
29
|
if (flags.stream) {
|
|
27
30
|
for await (const line of client.stream('/v1/responses', payload)) {
|
|
@@ -45,22 +48,38 @@ export default class ChatResponses extends BaseCommand {
|
|
|
45
48
|
process.stdout.write('\n');
|
|
46
49
|
return {};
|
|
47
50
|
}
|
|
48
|
-
const data =
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
const { data, headers } = await client.postWithHeaders('/v1/responses', { body: payload });
|
|
52
|
+
const body = data;
|
|
53
|
+
if (this.jsonEnabled()) {
|
|
54
|
+
const meta = {};
|
|
55
|
+
if (headers['x-faces-provider'])
|
|
56
|
+
meta.provider = headers['x-faces-provider'];
|
|
57
|
+
if (headers['x-faces-cost-usd'])
|
|
58
|
+
meta.cost_usd = headers['x-faces-cost-usd'];
|
|
59
|
+
if (Object.keys(meta).length > 0)
|
|
60
|
+
body._meta = meta;
|
|
61
|
+
return body;
|
|
62
|
+
}
|
|
51
63
|
let outputText = '';
|
|
52
|
-
for (const item of
|
|
64
|
+
for (const item of body.output ?? []) {
|
|
53
65
|
for (const block of item.content ?? []) {
|
|
54
66
|
if (block.type === 'output_text')
|
|
55
67
|
outputText += String(block.text ?? '');
|
|
56
68
|
}
|
|
57
69
|
}
|
|
58
70
|
this.log(outputText);
|
|
59
|
-
return
|
|
71
|
+
return body;
|
|
60
72
|
}
|
|
61
73
|
catch (err) {
|
|
62
|
-
if (err instanceof FacesAPIError)
|
|
74
|
+
if (err instanceof FacesAPIError) {
|
|
75
|
+
if (err.errorCode === 'oauth_rejected') {
|
|
76
|
+
const hint = err.fallbackAvailable
|
|
77
|
+
? 'Run `faces account:preferences api_fallback true` to allow paid fallback.'
|
|
78
|
+
: 'Run `faces billing:topup` to add credits, then enable fallback with `faces account:preferences api_fallback true`.';
|
|
79
|
+
this.error(`OAuth failed: ${err.message}\n${hint}`);
|
|
80
|
+
}
|
|
63
81
|
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
82
|
+
}
|
|
64
83
|
throw err;
|
|
65
84
|
}
|
|
66
85
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base.js';
|
|
2
|
+
export default class CompileAll extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
timeout: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
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
|
+
run(): Promise<unknown>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { BaseCommand } from '../../base.js';
|
|
3
|
+
import { FacesAPIError } from '../../client.js';
|
|
4
|
+
import { pollCompileProgress } from '../../poll.js';
|
|
5
|
+
export default class CompileAll extends BaseCommand {
|
|
6
|
+
static description = 'Compile all uncompiled documents and threads across all faces';
|
|
7
|
+
static flags = {
|
|
8
|
+
...BaseCommand.baseFlags,
|
|
9
|
+
timeout: Flags.integer({ description: 'Per-item compile timeout in seconds (default: 600)', default: 600 }),
|
|
10
|
+
};
|
|
11
|
+
async run() {
|
|
12
|
+
const { flags } = await this.parse(CompileAll);
|
|
13
|
+
const client = this.makeClient(flags);
|
|
14
|
+
const json = this.jsonEnabled();
|
|
15
|
+
// Fetch all faces
|
|
16
|
+
let faces;
|
|
17
|
+
try {
|
|
18
|
+
const resp = await client.get('/v1/faces');
|
|
19
|
+
faces = (resp.data ?? resp);
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
if (err instanceof FacesAPIError)
|
|
23
|
+
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
24
|
+
throw err;
|
|
25
|
+
}
|
|
26
|
+
// Collect uncompiled items
|
|
27
|
+
const items = [];
|
|
28
|
+
for (const face of faces) {
|
|
29
|
+
const alias = face.alias;
|
|
30
|
+
if (face.formula)
|
|
31
|
+
continue; // composite faces have no source material
|
|
32
|
+
// Check documents
|
|
33
|
+
try {
|
|
34
|
+
const docs = await client.get('/v1/compile/documents', { params: { alias } });
|
|
35
|
+
for (const doc of docs) {
|
|
36
|
+
const status = doc.prepare_status;
|
|
37
|
+
if (status !== 'synced' && status !== 'ready') {
|
|
38
|
+
items.push({
|
|
39
|
+
type: 'document',
|
|
40
|
+
id: doc.document_id,
|
|
41
|
+
alias,
|
|
42
|
+
label: doc.label ?? null,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch { /* no docs */ }
|
|
48
|
+
// Check threads
|
|
49
|
+
try {
|
|
50
|
+
const threads = await client.get('/v1/compile/threads', { params: { alias } });
|
|
51
|
+
for (const thread of threads) {
|
|
52
|
+
const status = thread.prepare_status;
|
|
53
|
+
if (status !== 'synced' && status !== 'ready') {
|
|
54
|
+
items.push({
|
|
55
|
+
type: 'thread',
|
|
56
|
+
id: thread.thread_id,
|
|
57
|
+
alias,
|
|
58
|
+
label: thread.label ?? null,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch { /* no threads */ }
|
|
64
|
+
}
|
|
65
|
+
if (items.length === 0) {
|
|
66
|
+
if (!json)
|
|
67
|
+
this.log('Nothing to compile — all documents and threads are up to date.');
|
|
68
|
+
return { compiled: 0, failed: 0, items: [] };
|
|
69
|
+
}
|
|
70
|
+
if (!json)
|
|
71
|
+
this.log(`Found ${items.length} item(s) to compile\n`);
|
|
72
|
+
let compiled = 0;
|
|
73
|
+
let failed = 0;
|
|
74
|
+
const results = [];
|
|
75
|
+
for (let i = 0; i < items.length; i++) {
|
|
76
|
+
const item = items[i];
|
|
77
|
+
const tag = `[${i + 1}/${items.length}]`;
|
|
78
|
+
const name = item.label ?? item.id.slice(0, 8);
|
|
79
|
+
if (!json)
|
|
80
|
+
process.stderr.write(`${tag} ${item.type} "${name}" (${item.alias})... `);
|
|
81
|
+
const makeEndpoint = item.type === 'document'
|
|
82
|
+
? `/v1/compile/documents/${item.id}/make`
|
|
83
|
+
: `/v1/compile/threads/${item.id}/make`;
|
|
84
|
+
const pollEndpoint = item.type === 'document'
|
|
85
|
+
? `/v1/compile/documents/${item.id}`
|
|
86
|
+
: `/v1/compile/threads/${item.id}`;
|
|
87
|
+
try {
|
|
88
|
+
await client.post(makeEndpoint);
|
|
89
|
+
await pollCompileProgress(client, item.id, {
|
|
90
|
+
timeoutMs: flags.timeout * 1000,
|
|
91
|
+
endpoint: pollEndpoint,
|
|
92
|
+
onProgress: (p) => {
|
|
93
|
+
if (!json) {
|
|
94
|
+
process.stderr.write(`[${p.chunks_completed ?? '?'}/${p.chunks_total ?? '?'}] `);
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
compiled++;
|
|
99
|
+
results.push({ ...item, status: 'compiled' });
|
|
100
|
+
if (!json)
|
|
101
|
+
process.stderr.write('done\n');
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
failed++;
|
|
105
|
+
const msg = err instanceof FacesAPIError ? `${err.statusCode}: ${err.message}` : err instanceof Error ? err.message : String(err);
|
|
106
|
+
results.push({ ...item, status: `failed: ${msg}` });
|
|
107
|
+
if (!json)
|
|
108
|
+
process.stderr.write(`failed: ${msg}\n`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (!json) {
|
|
112
|
+
this.log(`\nCompile complete: ${compiled} succeeded, ${failed} failed`);
|
|
113
|
+
}
|
|
114
|
+
return { compiled, failed, items: results };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -3,6 +3,7 @@ export default class CompileThreadCreate extends BaseCommand {
|
|
|
3
3
|
static description: string;
|
|
4
4
|
static flags: {
|
|
5
5
|
label: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
'oauth-only': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
6
7
|
'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
8
|
token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
9
|
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -6,6 +6,7 @@ export default class CompileThreadCreate extends BaseCommand {
|
|
|
6
6
|
static flags = {
|
|
7
7
|
...BaseCommand.baseFlags,
|
|
8
8
|
label: Flags.string({ description: 'Thread label' }),
|
|
9
|
+
'oauth-only': Flags.boolean({ description: 'Prevent fallback to paid system key (use OAuth only)', default: false }),
|
|
9
10
|
};
|
|
10
11
|
static args = {
|
|
11
12
|
face_id: Args.string({ description: 'Face alias', required: true }),
|
|
@@ -16,13 +17,22 @@ export default class CompileThreadCreate extends BaseCommand {
|
|
|
16
17
|
const payload = { alias: args.face_id };
|
|
17
18
|
if (flags.label)
|
|
18
19
|
payload.label = flags.label;
|
|
20
|
+
if (flags['oauth-only'])
|
|
21
|
+
payload.oauth_only = true;
|
|
19
22
|
let data;
|
|
20
23
|
try {
|
|
21
24
|
data = await client.post('/v1/compile/threads', { body: payload });
|
|
22
25
|
}
|
|
23
26
|
catch (err) {
|
|
24
|
-
if (err instanceof FacesAPIError)
|
|
27
|
+
if (err instanceof FacesAPIError) {
|
|
28
|
+
if (err.errorCode === 'oauth_rejected') {
|
|
29
|
+
const hint = err.fallbackAvailable
|
|
30
|
+
? 'Run `faces account:preferences api_fallback true` to allow paid fallback.'
|
|
31
|
+
: 'Run `faces billing:topup` to add credits, then enable fallback with `faces account:preferences api_fallback true`.';
|
|
32
|
+
this.error(`OAuth failed: ${err.message}\n${hint}`);
|
|
33
|
+
}
|
|
25
34
|
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
35
|
+
}
|
|
26
36
|
throw err;
|
|
27
37
|
}
|
|
28
38
|
if (!this.jsonEnabled())
|
|
@@ -3,6 +3,7 @@ export default class CompileThreadMessage extends BaseCommand {
|
|
|
3
3
|
static description: string;
|
|
4
4
|
static flags: {
|
|
5
5
|
message: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
'oauth-only': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
6
7
|
'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
8
|
token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
9
|
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -6,6 +6,7 @@ export default class CompileThreadMessage extends BaseCommand {
|
|
|
6
6
|
static flags = {
|
|
7
7
|
...BaseCommand.baseFlags,
|
|
8
8
|
message: Flags.string({ char: 'm', description: 'User message to append', required: true }),
|
|
9
|
+
'oauth-only': Flags.boolean({ description: 'Prevent fallback to paid system key (use OAuth only)', default: false }),
|
|
9
10
|
};
|
|
10
11
|
static args = {
|
|
11
12
|
thread_id: Args.string({ description: 'Thread ID', required: true }),
|
|
@@ -13,15 +14,25 @@ export default class CompileThreadMessage extends BaseCommand {
|
|
|
13
14
|
async run() {
|
|
14
15
|
const { args, flags } = await this.parse(CompileThreadMessage);
|
|
15
16
|
const client = this.makeClient(flags);
|
|
17
|
+
const payload = { message: flags.message };
|
|
18
|
+
if (flags['oauth-only'])
|
|
19
|
+
payload.oauth_only = true;
|
|
16
20
|
let data;
|
|
17
21
|
try {
|
|
18
22
|
data = await client.post(`/v1/compile/threads/${args.thread_id}/messages`, {
|
|
19
|
-
body:
|
|
23
|
+
body: payload,
|
|
20
24
|
});
|
|
21
25
|
}
|
|
22
26
|
catch (err) {
|
|
23
|
-
if (err instanceof FacesAPIError)
|
|
27
|
+
if (err instanceof FacesAPIError) {
|
|
28
|
+
if (err.errorCode === 'oauth_rejected') {
|
|
29
|
+
const hint = err.fallbackAvailable
|
|
30
|
+
? 'Run `faces account:preferences api_fallback true` to allow paid fallback.'
|
|
31
|
+
: 'Run `faces billing:topup` to add credits, then enable fallback with `faces account:preferences api_fallback true`.';
|
|
32
|
+
this.error(`OAuth failed: ${err.message}\n${hint}`);
|
|
33
|
+
}
|
|
24
34
|
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
35
|
+
}
|
|
25
36
|
throw err;
|
|
26
37
|
}
|
|
27
38
|
if (!this.jsonEnabled())
|