faces-cli 1.3.2 → 1.4.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/catalog.d.ts +36 -0
- package/dist/catalog.js +167 -0
- package/dist/client.js +2 -1
- package/dist/commands/auth/whoami.js +1 -1
- package/dist/commands/catalog/doctor.d.ts +12 -0
- package/dist/commands/catalog/doctor.js +196 -0
- package/dist/commands/catalog/list.d.ts +10 -0
- package/dist/commands/catalog/list.js +35 -0
- package/dist/commands/chat/chat.d.ts +4 -0
- package/dist/commands/chat/chat.js +146 -39
- package/dist/commands/chat/messages.js +1 -1
- package/dist/commands/chat/responses.js +1 -1
- package/dist/commands/compile/doc/create.d.ts +1 -0
- package/dist/commands/compile/doc/create.js +5 -2
- package/dist/commands/compile/doc/edit.d.ts +17 -0
- package/dist/commands/compile/doc/edit.js +48 -0
- package/dist/commands/compile/doc/index.d.ts +18 -0
- package/dist/commands/compile/doc/index.js +95 -0
- package/dist/commands/compile/doc/list.js +1 -1
- package/dist/commands/compile/doc/make.d.ts +14 -0
- package/dist/commands/compile/doc/make.js +55 -0
- package/dist/commands/compile/import.js +2 -3
- package/dist/commands/compile/thread/create.js +2 -2
- package/dist/commands/compile/{doc/sync.d.ts → thread/delete.d.ts} +2 -2
- package/dist/commands/compile/{doc/sync.js → thread/delete.js} +7 -7
- package/dist/commands/compile/thread/edit.d.ts +14 -0
- package/dist/commands/compile/thread/edit.js +29 -0
- package/dist/commands/compile/{doc/prepare.d.ts → thread/get.d.ts} +2 -2
- package/dist/commands/compile/{doc/prepare.js → thread/get.js} +5 -5
- package/dist/commands/compile/thread/list.js +1 -1
- package/dist/commands/compile/thread/message.js +1 -1
- package/dist/commands/face/create.d.ts +2 -0
- package/dist/commands/face/create.js +17 -2
- package/dist/commands/face/delete.js +6 -0
- package/dist/commands/face/get.js +5 -3
- package/dist/commands/face/list.js +20 -3
- package/dist/commands/face/update.d.ts +2 -0
- package/dist/commands/face/update.js +39 -9
- package/dist/config.d.ts +2 -0
- package/dist/poll.d.ts +30 -0
- package/dist/poll.js +40 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +16 -0
- package/oclif.manifest.json +1154 -661
- package/package.json +4 -1
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import { BaseCommand } from '../../../base.js';
|
|
3
|
+
import { FacesAPIError } from '../../../client.js';
|
|
4
|
+
export default class CompileThreadEdit extends BaseCommand {
|
|
5
|
+
static description = 'Edit a thread (label)';
|
|
6
|
+
static flags = {
|
|
7
|
+
...BaseCommand.baseFlags,
|
|
8
|
+
label: Flags.string({ description: 'New thread label', required: true }),
|
|
9
|
+
};
|
|
10
|
+
static args = {
|
|
11
|
+
thread_id: Args.string({ description: 'Thread ID', required: true }),
|
|
12
|
+
};
|
|
13
|
+
async run() {
|
|
14
|
+
const { args, flags } = await this.parse(CompileThreadEdit);
|
|
15
|
+
const client = this.makeClient(flags);
|
|
16
|
+
let data;
|
|
17
|
+
try {
|
|
18
|
+
data = await client.patch(`/v1/compile/threads/${args.thread_id}`, { body: { label: flags.label } });
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
if (err instanceof FacesAPIError)
|
|
22
|
+
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
23
|
+
throw err;
|
|
24
|
+
}
|
|
25
|
+
if (!this.jsonEnabled())
|
|
26
|
+
this.printHuman(data);
|
|
27
|
+
return data;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BaseCommand } from '../../../base.js';
|
|
2
|
-
export default class
|
|
2
|
+
export default class CompileThreadGet extends BaseCommand {
|
|
3
3
|
static description: string;
|
|
4
4
|
static flags: {
|
|
5
5
|
'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -7,7 +7,7 @@ export default class CompileDocPrepare extends BaseCommand {
|
|
|
7
7
|
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
8
|
};
|
|
9
9
|
static args: {
|
|
10
|
-
|
|
10
|
+
thread_id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
11
11
|
};
|
|
12
12
|
run(): Promise<unknown>;
|
|
13
13
|
}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { Args } from '@oclif/core';
|
|
2
2
|
import { BaseCommand } from '../../../base.js';
|
|
3
3
|
import { FacesAPIError } from '../../../client.js';
|
|
4
|
-
export default class
|
|
5
|
-
static description = '
|
|
4
|
+
export default class CompileThreadGet extends BaseCommand {
|
|
5
|
+
static description = 'Get a thread by ID';
|
|
6
6
|
static flags = {
|
|
7
7
|
...BaseCommand.baseFlags,
|
|
8
8
|
};
|
|
9
9
|
static args = {
|
|
10
|
-
|
|
10
|
+
thread_id: Args.string({ description: 'Thread ID', required: true }),
|
|
11
11
|
};
|
|
12
12
|
async run() {
|
|
13
|
-
const { args, flags } = await this.parse(
|
|
13
|
+
const { args, flags } = await this.parse(CompileThreadGet);
|
|
14
14
|
const client = this.makeClient(flags);
|
|
15
15
|
let data;
|
|
16
16
|
try {
|
|
17
|
-
data = await client.
|
|
17
|
+
data = await client.get(`/v1/compile/threads/${args.thread_id}`);
|
|
18
18
|
}
|
|
19
19
|
catch (err) {
|
|
20
20
|
if (err instanceof FacesAPIError)
|
|
@@ -14,7 +14,7 @@ export default class CompileThreadList extends BaseCommand {
|
|
|
14
14
|
const client = this.makeClient(flags);
|
|
15
15
|
let data;
|
|
16
16
|
try {
|
|
17
|
-
data = await client.get(
|
|
17
|
+
data = await client.get('/v1/compile/threads', { params: { model: args.face_id } });
|
|
18
18
|
}
|
|
19
19
|
catch (err) {
|
|
20
20
|
if (err instanceof FacesAPIError)
|
|
@@ -16,7 +16,7 @@ export default class CompileThreadMessage extends BaseCommand {
|
|
|
16
16
|
let data;
|
|
17
17
|
try {
|
|
18
18
|
data = await client.post(`/v1/compile/threads/${args.thread_id}/messages`, {
|
|
19
|
-
body: {
|
|
19
|
+
body: { message: flags.message },
|
|
20
20
|
});
|
|
21
21
|
}
|
|
22
22
|
catch (err) {
|
|
@@ -4,6 +4,8 @@ export default class FaceCreate extends BaseCommand {
|
|
|
4
4
|
static flags: {
|
|
5
5
|
name: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
6
|
username: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
'default-model': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
9
|
formula: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
10
|
attr: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
11
|
tool: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { Flags } from '@oclif/core';
|
|
2
2
|
import { BaseCommand } from '../../base.js';
|
|
3
3
|
import { FacesAPIError } from '../../client.js';
|
|
4
|
+
import { CatalogService } from '../../catalog.js';
|
|
5
|
+
import { flattenBasicFacts } from '../../utils.js';
|
|
4
6
|
export default class FaceCreate extends BaseCommand {
|
|
5
7
|
static description = 'Create a new face';
|
|
6
8
|
static flags = {
|
|
7
9
|
...BaseCommand.baseFlags,
|
|
8
10
|
name: Flags.string({ description: 'Display name', required: true }),
|
|
9
11
|
username: Flags.string({ description: 'Unique username slug', required: true }),
|
|
12
|
+
description: Flags.string({ description: 'Description for local catalog' }),
|
|
13
|
+
'default-model': Flags.string({ description: 'Default LLM for chat (e.g. gpt-4o-mini, claude-sonnet-4-6)' }),
|
|
10
14
|
formula: Flags.string({ description: 'Boolean formula over owned concrete face usernames (e.g. "a | b", "(a | b) - c"). Creates a composite face.' }),
|
|
11
15
|
attr: Flags.string({ description: 'Attribute KEY=VALUE (repeatable)', multiple: true }),
|
|
12
16
|
tool: Flags.string({ description: 'Tool name to enable (repeatable)', multiple: true }),
|
|
@@ -31,9 +35,11 @@ export default class FaceCreate extends BaseCommand {
|
|
|
31
35
|
parsedAttrs[a.slice(0, idx).trim()] = a.slice(idx + 1).trim();
|
|
32
36
|
}
|
|
33
37
|
if (Object.keys(parsedAttrs).length > 0)
|
|
34
|
-
payload.
|
|
38
|
+
payload.basic_facts = parsedAttrs;
|
|
35
39
|
if (flags.tool && flags.tool.length > 0)
|
|
36
|
-
payload.
|
|
40
|
+
payload.default_tools = flags.tool;
|
|
41
|
+
if (flags['default-model'])
|
|
42
|
+
payload.default_model = flags['default-model'];
|
|
37
43
|
}
|
|
38
44
|
let data;
|
|
39
45
|
try {
|
|
@@ -44,6 +50,15 @@ export default class FaceCreate extends BaseCommand {
|
|
|
44
50
|
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
45
51
|
throw err;
|
|
46
52
|
}
|
|
53
|
+
const face = data;
|
|
54
|
+
if (face.basic_facts && typeof face.basic_facts === 'object') {
|
|
55
|
+
face.basic_facts = flattenBasicFacts(face.basic_facts);
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const catalog = new CatalogService();
|
|
59
|
+
catalog.writeFace(face, flags.description);
|
|
60
|
+
}
|
|
61
|
+
catch { /* catalog errors are non-fatal */ }
|
|
47
62
|
if (!this.jsonEnabled())
|
|
48
63
|
this.printHuman(data);
|
|
49
64
|
return data;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Args, Flags } from '@oclif/core';
|
|
2
2
|
import { BaseCommand } from '../../base.js';
|
|
3
3
|
import { FacesAPIError } from '../../client.js';
|
|
4
|
+
import { CatalogService } from '../../catalog.js';
|
|
4
5
|
import { createInterface } from 'node:readline';
|
|
5
6
|
export default class FaceDelete extends BaseCommand {
|
|
6
7
|
static description = 'Delete a face permanently';
|
|
@@ -28,6 +29,11 @@ export default class FaceDelete extends BaseCommand {
|
|
|
28
29
|
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
29
30
|
throw err;
|
|
30
31
|
}
|
|
32
|
+
try {
|
|
33
|
+
const catalog = new CatalogService();
|
|
34
|
+
catalog.deleteFace(args.face_id);
|
|
35
|
+
}
|
|
36
|
+
catch { /* catalog errors are non-fatal */ }
|
|
31
37
|
if (!this.jsonEnabled())
|
|
32
38
|
this.printHuman(data);
|
|
33
39
|
return data;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Args } from '@oclif/core';
|
|
2
2
|
import { BaseCommand } from '../../base.js';
|
|
3
3
|
import { FacesAPIError } from '../../client.js';
|
|
4
|
+
import { flattenBasicFacts } from '../../utils.js';
|
|
4
5
|
export default class FaceGet extends BaseCommand {
|
|
5
6
|
static description = 'Get details for a face by ID or username';
|
|
6
7
|
static flags = {
|
|
@@ -21,8 +22,10 @@ export default class FaceGet extends BaseCommand {
|
|
|
21
22
|
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
22
23
|
throw err;
|
|
23
24
|
}
|
|
25
|
+
const f = data;
|
|
26
|
+
if (f.basic_facts)
|
|
27
|
+
f.basic_facts = flattenBasicFacts(f.basic_facts);
|
|
24
28
|
if (!this.jsonEnabled()) {
|
|
25
|
-
const f = data;
|
|
26
29
|
this.log(`id: ${f.id}`);
|
|
27
30
|
this.log(`uid: ${f.uid}`);
|
|
28
31
|
this.log(`name: ${f.name}`);
|
|
@@ -37,8 +40,7 @@ export default class FaceGet extends BaseCommand {
|
|
|
37
40
|
if (f.basic_facts && Object.keys(f.basic_facts).length > 0) {
|
|
38
41
|
this.log('basic_facts:');
|
|
39
42
|
for (const [k, v] of Object.entries(f.basic_facts)) {
|
|
40
|
-
|
|
41
|
-
this.log(` ${k}: ${display}`);
|
|
43
|
+
this.log(` ${k}: ${v}`);
|
|
42
44
|
}
|
|
43
45
|
}
|
|
44
46
|
if (f.default_tools && f.default_tools.length > 0)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BaseCommand } from '../../base.js';
|
|
2
2
|
import { FacesAPIError } from '../../client.js';
|
|
3
|
+
import { flattenBasicFacts } from '../../utils.js';
|
|
3
4
|
export default class FaceList extends BaseCommand {
|
|
4
5
|
static description = 'List all owned faces';
|
|
5
6
|
static flags = {
|
|
@@ -17,8 +18,15 @@ export default class FaceList extends BaseCommand {
|
|
|
17
18
|
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
18
19
|
throw err;
|
|
19
20
|
}
|
|
21
|
+
// Flatten basic_facts in response
|
|
22
|
+
const raw = data.data ?? data;
|
|
23
|
+
for (const f of raw) {
|
|
24
|
+
if (f.basic_facts && typeof f.basic_facts === 'object') {
|
|
25
|
+
f.basic_facts = flattenBasicFacts(f.basic_facts);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
20
28
|
if (!this.jsonEnabled()) {
|
|
21
|
-
const faces =
|
|
29
|
+
const faces = raw;
|
|
22
30
|
if (faces.length === 0) {
|
|
23
31
|
this.log('(no faces)');
|
|
24
32
|
}
|
|
@@ -26,8 +34,17 @@ export default class FaceList extends BaseCommand {
|
|
|
26
34
|
const idWidth = Math.max(...faces.map(f => f.id.length));
|
|
27
35
|
const nameWidth = Math.max(...faces.map(f => f.name.length));
|
|
28
36
|
for (const f of faces) {
|
|
29
|
-
|
|
30
|
-
|
|
37
|
+
let suffix = '';
|
|
38
|
+
if (f.formula) {
|
|
39
|
+
suffix = ` [composite: ${f.formula}]`;
|
|
40
|
+
}
|
|
41
|
+
else if (f.component_counts || f.profile_token_count) {
|
|
42
|
+
const cc = f.component_counts;
|
|
43
|
+
const total = cc ? cc.alpha + cc.beta + cc.delta + cc.epsilon : 0;
|
|
44
|
+
const profile = f.profile_token_count ?? 0;
|
|
45
|
+
suffix = ` [profile: ${profile} tok, components: ${total}]`;
|
|
46
|
+
}
|
|
47
|
+
this.log(`${f.id.padEnd(idWidth)} ${f.name.padEnd(nameWidth)}${suffix}`);
|
|
31
48
|
}
|
|
32
49
|
}
|
|
33
50
|
}
|
|
@@ -3,6 +3,8 @@ export default class FaceUpdate extends BaseCommand {
|
|
|
3
3
|
static description: string;
|
|
4
4
|
static flags: {
|
|
5
5
|
name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
'default-model': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
8
|
formula: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
9
|
attr: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
10
|
tool: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { Args, Flags } from '@oclif/core';
|
|
2
2
|
import { BaseCommand } from '../../base.js';
|
|
3
3
|
import { FacesAPIError } from '../../client.js';
|
|
4
|
+
import { CatalogService } from '../../catalog.js';
|
|
5
|
+
import { flattenBasicFacts } from '../../utils.js';
|
|
4
6
|
export default class FaceUpdate extends BaseCommand {
|
|
5
7
|
static description = "Update a face's metadata";
|
|
6
8
|
static flags = {
|
|
7
9
|
...BaseCommand.baseFlags,
|
|
8
10
|
name: Flags.string({ description: 'New display name' }),
|
|
11
|
+
description: Flags.string({ description: 'Description for local catalog' }),
|
|
12
|
+
'default-model': Flags.string({ description: 'Default LLM for chat (e.g. gpt-4o-mini, claude-sonnet-4-6)' }),
|
|
9
13
|
formula: Flags.string({ description: 'New boolean formula (synthetic faces only)' }),
|
|
10
14
|
attr: Flags.string({ description: 'Update attribute KEY=VALUE (repeatable)', multiple: true }),
|
|
11
15
|
tool: Flags.string({ description: 'Tool names to set (replaces list, repeatable)', multiple: true }),
|
|
@@ -29,21 +33,47 @@ export default class FaceUpdate extends BaseCommand {
|
|
|
29
33
|
const idx = a.indexOf('=');
|
|
30
34
|
parsed[a.slice(0, idx).trim()] = a.slice(idx + 1).trim();
|
|
31
35
|
}
|
|
32
|
-
payload.
|
|
36
|
+
payload.basic_facts = parsed;
|
|
33
37
|
}
|
|
34
38
|
if (flags.tool && flags.tool.length > 0)
|
|
35
|
-
payload.
|
|
36
|
-
if (
|
|
39
|
+
payload.default_tools = flags.tool;
|
|
40
|
+
if (flags['default-model'])
|
|
41
|
+
payload.default_model = flags['default-model'];
|
|
42
|
+
const hasApiFields = Object.keys(payload).length > 0;
|
|
43
|
+
const hasDescription = Boolean(flags.description);
|
|
44
|
+
if (!hasApiFields && !hasDescription)
|
|
37
45
|
this.error('Provide at least one field to update.');
|
|
38
46
|
let data;
|
|
39
|
-
|
|
40
|
-
|
|
47
|
+
if (hasApiFields) {
|
|
48
|
+
try {
|
|
49
|
+
data = await client.patch(`/v1/faces/${args.face_id}`, { body: payload });
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
if (err instanceof FacesAPIError)
|
|
53
|
+
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
54
|
+
throw err;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// description-only update: fetch current face data for catalog
|
|
59
|
+
try {
|
|
60
|
+
data = await client.get(`/v1/faces/${args.face_id}`);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
if (err instanceof FacesAPIError)
|
|
64
|
+
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
65
|
+
throw err;
|
|
66
|
+
}
|
|
41
67
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
68
|
+
const face = data;
|
|
69
|
+
if (face.basic_facts && typeof face.basic_facts === 'object') {
|
|
70
|
+
face.basic_facts = flattenBasicFacts(face.basic_facts);
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
const catalog = new CatalogService();
|
|
74
|
+
catalog.writeFace(face, flags.description);
|
|
46
75
|
}
|
|
76
|
+
catch { /* catalog errors are non-fatal */ }
|
|
47
77
|
if (!this.jsonEnabled())
|
|
48
78
|
this.printHuman(data);
|
|
49
79
|
return data;
|
package/dist/config.d.ts
CHANGED
package/dist/poll.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared polling helper for document compile progress.
|
|
3
|
+
*
|
|
4
|
+
* Works with both /make (preparing → syncing → synced) and
|
|
5
|
+
* legacy /prepare (processing → ready) status flows.
|
|
6
|
+
*/
|
|
7
|
+
import { FacesClient } from './client.js';
|
|
8
|
+
export interface PollProgress {
|
|
9
|
+
prepare_status: string | null;
|
|
10
|
+
chunks_total: number | null;
|
|
11
|
+
chunks_completed: number | null;
|
|
12
|
+
current_counts: {
|
|
13
|
+
epsilon: number;
|
|
14
|
+
beta: number;
|
|
15
|
+
delta: number;
|
|
16
|
+
alpha: number;
|
|
17
|
+
} | null;
|
|
18
|
+
}
|
|
19
|
+
export interface PollOptions {
|
|
20
|
+
intervalMs?: number;
|
|
21
|
+
timeoutMs?: number;
|
|
22
|
+
onProgress?: (p: PollProgress) => void;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Poll GET /compile/documents/{docId} until a terminal status is reached.
|
|
26
|
+
* Terminal statuses: "synced" (from /make), "ready" (from /prepare), "failed".
|
|
27
|
+
* Returns the final GET response.
|
|
28
|
+
* Throws on timeout or failure.
|
|
29
|
+
*/
|
|
30
|
+
export declare function pollCompileProgress(client: FacesClient, docId: string, opts?: PollOptions): Promise<unknown>;
|
package/dist/poll.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Poll GET /compile/documents/{docId} until a terminal status is reached.
|
|
3
|
+
* Terminal statuses: "synced" (from /make), "ready" (from /prepare), "failed".
|
|
4
|
+
* Returns the final GET response.
|
|
5
|
+
* Throws on timeout or failure.
|
|
6
|
+
*/
|
|
7
|
+
export async function pollCompileProgress(client, docId, opts = {}) {
|
|
8
|
+
const interval = opts.intervalMs ?? 3000;
|
|
9
|
+
const timeout = opts.timeoutMs ?? 600_000;
|
|
10
|
+
const start = Date.now();
|
|
11
|
+
let lastChunks = -1;
|
|
12
|
+
while (true) {
|
|
13
|
+
if (Date.now() - start > timeout) {
|
|
14
|
+
throw new Error(`Compile timed out after ${Math.round(timeout / 1000)}s`);
|
|
15
|
+
}
|
|
16
|
+
await sleep(interval);
|
|
17
|
+
const data = await client.get(`/v1/compile/documents/${docId}`);
|
|
18
|
+
const progress = {
|
|
19
|
+
prepare_status: data.prepare_status ?? null,
|
|
20
|
+
chunks_total: data.chunks_total ?? null,
|
|
21
|
+
chunks_completed: data.chunks_completed ?? null,
|
|
22
|
+
current_counts: data.current_counts ?? null,
|
|
23
|
+
};
|
|
24
|
+
// Only fire callback when chunks change (skip initial 0/N state)
|
|
25
|
+
if (progress.chunks_completed !== lastChunks && (progress.chunks_completed ?? 0) > 0) {
|
|
26
|
+
lastChunks = progress.chunks_completed ?? -1;
|
|
27
|
+
opts.onProgress?.(progress);
|
|
28
|
+
}
|
|
29
|
+
if (progress.prepare_status === 'synced' || progress.prepare_status === 'ready') {
|
|
30
|
+
return data;
|
|
31
|
+
}
|
|
32
|
+
if (progress.prepare_status === 'failed') {
|
|
33
|
+
const error = data.error ?? 'Unknown error';
|
|
34
|
+
throw new Error(`Compile failed: ${error}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function sleep(ms) {
|
|
39
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
40
|
+
}
|
package/dist/utils.d.ts
ADDED
package/dist/utils.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flatten basic_facts from API's nested {value, status, identification} format
|
|
3
|
+
* to simple {key: value} strings.
|
|
4
|
+
*/
|
|
5
|
+
export function flattenBasicFacts(facts) {
|
|
6
|
+
const flat = {};
|
|
7
|
+
for (const [k, v] of Object.entries(facts)) {
|
|
8
|
+
if (typeof v === 'object' && v !== null && 'value' in v) {
|
|
9
|
+
flat[k] = String(v.value);
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
flat[k] = String(v);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return flat;
|
|
16
|
+
}
|