faces-cli 1.8.2 → 1.8.4
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/commands/style/revert.js +9 -12
- package/dist/commands/team/add.d.ts +1 -0
- package/dist/commands/team/add.js +10 -15
- package/dist/commands/team/members.d.ts +1 -0
- package/dist/commands/team/members.js +53 -4
- package/oclif.manifest.json +1527 -1519
- package/package.json +1 -1
|
@@ -3,9 +3,10 @@ import { BaseCommand } from '../../base.js';
|
|
|
3
3
|
import { FacesAPIError } from '../../client.js';
|
|
4
4
|
import { VERSIONS_PATH } from '../../style.js';
|
|
5
5
|
export default class StyleRevert extends BaseCommand {
|
|
6
|
-
static description = 'Go back to the style a face had before the last style:make.
|
|
7
|
-
'
|
|
8
|
-
'
|
|
6
|
+
static description = 'Go back to the style a face had before the last style:make. Two versions are kept per medium, so ' +
|
|
7
|
+
'this is a toggle: running it again returns to where you started. A face holds one style per medium, ' +
|
|
8
|
+
'so name which one with --medium when it has more than one. It changes how the face writes ' +
|
|
9
|
+
'immediately, so it asks first.';
|
|
9
10
|
static examples = [
|
|
10
11
|
'<%= config.bin %> <%= command.id %> alice --yes',
|
|
11
12
|
'<%= config.bin %> <%= command.id %> alice --medium email --yes',
|
|
@@ -50,13 +51,6 @@ export default class StyleRevert extends BaseCommand {
|
|
|
50
51
|
if (err.statusCode === 409) {
|
|
51
52
|
this.error(`Error (409): ${err.message}\nSee what is there: faces style:versions ${args.alias}`);
|
|
52
53
|
}
|
|
53
|
-
// Reverting a named medium currently fails this way even when the
|
|
54
|
-
// server itself reports can_revert: true (faces-backend-shared#590).
|
|
55
|
-
if (err.statusCode === 500) {
|
|
56
|
-
this.error(`Error (500): the server failed to revert '${args.alias}'.\n` +
|
|
57
|
-
'Reverting a per-medium style is currently broken upstream and nothing was changed. ' +
|
|
58
|
-
'Tracked as faces-backend-shared#590.');
|
|
59
|
-
}
|
|
60
54
|
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
61
55
|
}
|
|
62
56
|
throw err;
|
|
@@ -71,8 +65,11 @@ export default class StyleRevert extends BaseCommand {
|
|
|
71
65
|
else {
|
|
72
66
|
this.log(`'${args.alias}' reverted.`);
|
|
73
67
|
}
|
|
74
|
-
|
|
75
|
-
|
|
68
|
+
// Reverting again returns to where you started — it is a toggle between the
|
|
69
|
+
// two kept versions, not a walk backwards. Name the version it goes back to
|
|
70
|
+
// so the user does not have to hold it in their head.
|
|
71
|
+
const back = from === undefined ? '' : ` to return to version ${from}`;
|
|
72
|
+
this.log(`Run it again${back}. List versions: faces style:versions ${args.alias}`);
|
|
76
73
|
return data;
|
|
77
74
|
}
|
|
78
75
|
}
|
|
@@ -4,8 +4,8 @@ import { FacesAPIError } from '../../client.js';
|
|
|
4
4
|
import { TeamCatalogService } from '../../team-catalog.js';
|
|
5
5
|
import { resolveFace } from '../../utils.js';
|
|
6
6
|
export default class TeamAdd extends BaseCommand {
|
|
7
|
-
static description = 'Add face(s) to a team.
|
|
8
|
-
'
|
|
7
|
+
static description = 'Add face(s) to a team. Any face this account can reach may join: your own, a published one, or one ' +
|
|
8
|
+
'shared with you. Name someone else\'s as owner:alias, the same address chat uses.';
|
|
9
9
|
static flags = {
|
|
10
10
|
...BaseCommand.baseFlags,
|
|
11
11
|
face: Flags.string({ description: 'Face alias to add (repeatable)', multiple: true, required: true }),
|
|
@@ -13,13 +13,17 @@ export default class TeamAdd extends BaseCommand {
|
|
|
13
13
|
static args = {
|
|
14
14
|
team_id: Args.string({ description: 'Team ID', required: true }),
|
|
15
15
|
};
|
|
16
|
+
static examples = [
|
|
17
|
+
'<%= config.bin %> <%= command.id %> TEAM_ID --face alice --face bob',
|
|
18
|
+
'<%= config.bin %> <%= command.id %> TEAM_ID --face head:socrates',
|
|
19
|
+
];
|
|
16
20
|
async run() {
|
|
17
21
|
const { args, flags } = await this.parse(TeamAdd);
|
|
18
22
|
const client = this.makeClient(flags);
|
|
19
|
-
// Resolve
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
+
// Resolve to iam_ids. The members endpoint takes a uid or an owner:alias
|
|
24
|
+
// and not a bare alias, so resolving here means a user can name any face
|
|
25
|
+
// the way they already name it everywhere else. resolveFace also finds
|
|
26
|
+
// published and shared faces, which the plain face route cannot.
|
|
23
27
|
const iamIds = [];
|
|
24
28
|
for (const alias of flags.face) {
|
|
25
29
|
let resolved;
|
|
@@ -36,15 +40,6 @@ export default class TeamAdd extends BaseCommand {
|
|
|
36
40
|
}
|
|
37
41
|
throw err;
|
|
38
42
|
}
|
|
39
|
-
// The server enforces this too, but only once it has an id, which this
|
|
40
|
-
// command cannot reach for a face it does not own. Say the real reason.
|
|
41
|
-
if (!resolved.owned) {
|
|
42
|
-
this.error(`A team may only contain faces you own, and '${resolved.handle}' is owned by ` +
|
|
43
|
-
`'${resolved.owner ?? 'another account'}'. It is published or shared with you, so you can chat ` +
|
|
44
|
-
`it as ${resolved.handle}@<model>, but it cannot be a team member.\n` +
|
|
45
|
-
'Do not create a copy to work around this: the copy would be a different face with different ' +
|
|
46
|
-
'compiled material.');
|
|
47
|
-
}
|
|
48
43
|
const face = resolved.face;
|
|
49
44
|
const id = (face.uid ?? face.id ?? face.iam_id);
|
|
50
45
|
if (!id)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BaseCommand } from '../../base.js';
|
|
2
2
|
export default class TeamMembers extends BaseCommand {
|
|
3
3
|
static description: string;
|
|
4
|
+
static examples: string[];
|
|
4
5
|
static flags: {
|
|
5
6
|
'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
7
|
token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
import { Args } from '@oclif/core';
|
|
2
2
|
import { BaseCommand } from '../../base.js';
|
|
3
3
|
import { FacesAPIError } from '../../client.js';
|
|
4
|
+
/**
|
|
5
|
+
* Why a member can no longer be reached, in the terms a user can act on.
|
|
6
|
+
*
|
|
7
|
+
* The two are kept apart deliberately: access can be granted again, a deleted
|
|
8
|
+
* face cannot come back. Rendering them the same would tell someone to go and
|
|
9
|
+
* ask for something that no longer exists.
|
|
10
|
+
*/
|
|
11
|
+
const REASONS = {
|
|
12
|
+
unpublished_or_unshared: 'access was revoked by its owner',
|
|
13
|
+
deleted: 'the face was deleted',
|
|
14
|
+
};
|
|
4
15
|
export default class TeamMembers extends BaseCommand {
|
|
5
|
-
static description = 'List members of a team'
|
|
16
|
+
static description = 'List members of a team. A member you do not own can stop being reachable if its owner revokes ' +
|
|
17
|
+
'access or deletes it; those are listed with the reason rather than dropped.';
|
|
18
|
+
static examples = ['<%= config.bin %> <%= command.id %> TEAM_ID', '<%= config.bin %> <%= command.id %> TEAM_ID --json'];
|
|
6
19
|
static flags = {
|
|
7
20
|
...BaseCommand.baseFlags,
|
|
8
21
|
};
|
|
@@ -17,12 +30,48 @@ export default class TeamMembers extends BaseCommand {
|
|
|
17
30
|
data = await client.get(`/v1/teams/${args.team_id}/members`);
|
|
18
31
|
}
|
|
19
32
|
catch (err) {
|
|
20
|
-
if (err instanceof FacesAPIError)
|
|
33
|
+
if (err instanceof FacesAPIError) {
|
|
34
|
+
if (err.statusCode === 404)
|
|
35
|
+
this.error(`No team '${args.team_id}'. It does not exist, or is not yours.`);
|
|
21
36
|
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
37
|
+
}
|
|
22
38
|
throw err;
|
|
23
39
|
}
|
|
24
|
-
if (
|
|
25
|
-
|
|
40
|
+
if (this.jsonEnabled())
|
|
41
|
+
return data;
|
|
42
|
+
const members = (data.data ?? data) ?? [];
|
|
43
|
+
if (members.length === 0) {
|
|
44
|
+
this.log('This team has no members.');
|
|
45
|
+
this.log(`Add one with: faces team:add ${args.team_id} --face <alias>`);
|
|
46
|
+
return data;
|
|
47
|
+
}
|
|
48
|
+
const rows = members.map((m) => ({
|
|
49
|
+
alias: m.alias?.trim() || '(unknown)',
|
|
50
|
+
// reachable is absent on older servers; only an explicit false is a problem.
|
|
51
|
+
status: m.reachable === false
|
|
52
|
+
? `unreachable - ${REASONS[m.unreachable_reason ?? ''] ?? m.unreachable_reason ?? 'reason not given'}`
|
|
53
|
+
: 'ok',
|
|
54
|
+
id: m.iam_id ?? '-',
|
|
55
|
+
}));
|
|
56
|
+
const cols = [
|
|
57
|
+
['FACE', (r) => r.alias],
|
|
58
|
+
['STATUS', (r) => r.status],
|
|
59
|
+
['ID', (r) => r.id],
|
|
60
|
+
];
|
|
61
|
+
const w = cols.map(([h, g]) => Math.max(h.length, ...rows.map((r) => g(r).length)));
|
|
62
|
+
const line = (c) => c.map((x, i) => x.padEnd(w[i])).join(' ').trimEnd();
|
|
63
|
+
this.log(line(cols.map(([h]) => h)));
|
|
64
|
+
for (const r of rows)
|
|
65
|
+
this.log(line(cols.map(([, g]) => g(r))));
|
|
66
|
+
const lost = members.filter((m) => m.reachable === false);
|
|
67
|
+
this.log('');
|
|
68
|
+
this.log(`${rows.length} member(s).`);
|
|
69
|
+
if (lost.length > 0) {
|
|
70
|
+
// Say it plainly: a team that silently changed shape is the thing this
|
|
71
|
+
// reporting exists to prevent.
|
|
72
|
+
this.log(`${lost.length} can no longer be reached and will not answer. They are still listed because the ` +
|
|
73
|
+
'team has not changed; remove them with faces team:remove.');
|
|
74
|
+
}
|
|
26
75
|
return data;
|
|
27
76
|
}
|
|
28
77
|
}
|