@antasphere/chassis-cli 0.0.0-stage → 1.0.1

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.
Files changed (117) hide show
  1. package/LICENSE +82 -0
  2. package/dist/commands/auth.d.ts +6 -0
  3. package/dist/commands/auth.d.ts.map +1 -0
  4. package/dist/commands/auth.js +582 -0
  5. package/dist/commands/auth.js.map +1 -0
  6. package/dist/commands/completion.d.ts +5 -0
  7. package/dist/commands/completion.d.ts.map +1 -0
  8. package/dist/commands/completion.js +85 -0
  9. package/dist/commands/completion.js.map +1 -0
  10. package/dist/commands/demo.d.ts +12 -0
  11. package/dist/commands/demo.d.ts.map +1 -0
  12. package/dist/commands/demo.js +210 -0
  13. package/dist/commands/demo.js.map +1 -0
  14. package/dist/commands/files.d.ts +21 -0
  15. package/dist/commands/files.d.ts.map +1 -0
  16. package/dist/commands/files.js +178 -0
  17. package/dist/commands/files.js.map +1 -0
  18. package/dist/commands/projects.d.ts +38 -0
  19. package/dist/commands/projects.d.ts.map +1 -0
  20. package/dist/commands/projects.js +386 -0
  21. package/dist/commands/projects.js.map +1 -0
  22. package/dist/commands/teams.d.ts +46 -0
  23. package/dist/commands/teams.d.ts.map +1 -0
  24. package/dist/commands/teams.js +265 -0
  25. package/dist/commands/teams.js.map +1 -0
  26. package/dist/commands/workspaces.d.ts +22 -0
  27. package/dist/commands/workspaces.d.ts.map +1 -0
  28. package/dist/commands/workspaces.js +116 -0
  29. package/dist/commands/workspaces.js.map +1 -0
  30. package/dist/config.d.ts +29 -0
  31. package/dist/config.d.ts.map +1 -0
  32. package/dist/config.js +54 -0
  33. package/dist/config.js.map +1 -0
  34. package/dist/context.d.ts +152 -0
  35. package/dist/context.d.ts.map +1 -0
  36. package/dist/context.js +456 -0
  37. package/dist/context.js.map +1 -0
  38. package/dist/identity.d.ts +36 -0
  39. package/dist/identity.d.ts.map +1 -0
  40. package/dist/identity.js +18 -0
  41. package/dist/identity.js.map +1 -0
  42. package/dist/index.d.ts +24 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +31 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/kit.d.ts +46 -0
  47. package/dist/kit.d.ts.map +1 -0
  48. package/dist/kit.js +2 -0
  49. package/dist/kit.js.map +1 -0
  50. package/dist/open.d.ts +27 -0
  51. package/dist/open.d.ts.map +1 -0
  52. package/dist/open.js +45 -0
  53. package/dist/open.js.map +1 -0
  54. package/dist/owner-session.d.ts +34 -0
  55. package/dist/owner-session.d.ts.map +1 -0
  56. package/dist/owner-session.js +106 -0
  57. package/dist/owner-session.js.map +1 -0
  58. package/dist/program.d.ts +5 -0
  59. package/dist/program.d.ts.map +1 -0
  60. package/dist/program.js +150 -0
  61. package/dist/program.js.map +1 -0
  62. package/dist/safe-write.d.ts +46 -0
  63. package/dist/safe-write.d.ts.map +1 -0
  64. package/dist/safe-write.js +127 -0
  65. package/dist/safe-write.js.map +1 -0
  66. package/dist/stdin.d.ts +4 -0
  67. package/dist/stdin.d.ts.map +1 -0
  68. package/dist/stdin.js +36 -0
  69. package/dist/stdin.js.map +1 -0
  70. package/dist/testing/index.d.ts +70 -0
  71. package/dist/testing/index.d.ts.map +1 -0
  72. package/dist/testing/index.js +67 -0
  73. package/dist/testing/index.js.map +1 -0
  74. package/dist/workspace.d.ts +79 -0
  75. package/dist/workspace.d.ts.map +1 -0
  76. package/dist/workspace.js +139 -0
  77. package/dist/workspace.js.map +1 -0
  78. package/package.json +43 -3
  79. package/src/commands/auth.ts +687 -0
  80. package/src/commands/completion.ts +102 -0
  81. package/src/commands/demo.ts +271 -0
  82. package/src/commands/files.ts +197 -0
  83. package/src/commands/projects.ts +460 -0
  84. package/src/commands/teams.ts +320 -0
  85. package/src/commands/workspaces.ts +140 -0
  86. package/src/config.ts +81 -0
  87. package/src/context.ts +616 -0
  88. package/src/identity.ts +48 -0
  89. package/src/index.ts +70 -0
  90. package/src/kit.ts +50 -0
  91. package/src/open.ts +48 -0
  92. package/src/owner-session.ts +152 -0
  93. package/src/program.ts +183 -0
  94. package/src/safe-write.ts +136 -0
  95. package/src/stdin.ts +39 -0
  96. package/src/testing/index.ts +129 -0
  97. package/src/workspace.ts +229 -0
  98. package/test/host/identity.test.ts +229 -0
  99. package/test/host/minimal-host.ts +16 -0
  100. package/test/host/minimal-tool.ts +40 -0
  101. package/test/suite/cli.test.ts +301 -0
  102. package/test/suite/config.test.ts +59 -0
  103. package/test/suite/demo.test.ts +467 -0
  104. package/test/suite/hub-profile-shared.test.ts +123 -0
  105. package/test/suite/login.test.ts +743 -0
  106. package/test/suite/logout.test.ts +247 -0
  107. package/test/suite/migration.test.ts +109 -0
  108. package/test/suite/open.test.ts +59 -0
  109. package/test/suite/profiles.test.ts +380 -0
  110. package/test/suite/projects.test.ts +550 -0
  111. package/test/suite/recovery.test.ts +348 -0
  112. package/test/suite/security.test.ts +199 -0
  113. package/test/suite/signin-fixtures.ts +204 -0
  114. package/test/suite/teams.test.ts +354 -0
  115. package/test/suite/whoami.test.ts +159 -0
  116. package/test/suite/workspace.test.ts +402 -0
  117. package/README.md +0 -3
@@ -0,0 +1,38 @@
1
+ import type { Command } from 'commander';
2
+ import { PlatformApiError, type ChassisClient } from '@antasphere/chassis-sdk';
3
+ import { type CliIo } from '../context.js';
4
+ import type { CliKit } from '../kit.js';
5
+ /**
6
+ * The membership argument: an `@` makes it an email, anything else a user id.
7
+ * Better Auth ids are opaque text, so there is no id shape to test for — but
8
+ * an email always carries the `@`, and a user id never may (the server reads
9
+ * exactly one of the two fields, so guessing wrong is a `member_not_found`
10
+ * rather than a silent mismatch).
11
+ */
12
+ export declare function memberRef(value: string): {
13
+ email: string;
14
+ } | {
15
+ userId: string;
16
+ };
17
+ /**
18
+ * What the command was looking for, which is the ONE thing the wire cannot
19
+ * say: `member_not_found` means "nobody in this workspace matches" on `add`
20
+ * (the lookup is workspace-wide) and "not a member of this project" on
21
+ * `role` / `remove` (the lookup is inside the project). Same code, two
22
+ * different things to do about it.
23
+ */
24
+ export type ProjectLookup = 'project' | 'workspace-member' | 'project-member' | 'workspace-team' | 'project-team';
25
+ /**
26
+ * The role an `insufficient_project_role` answer names (`This needs the
27
+ * editor role on the project`), or null when the wire says none: the one
28
+ * place the sentence is parsed, for the chassis verbs and a tool's own.
29
+ */
30
+ export declare function roleNamedBy(e: PlatformApiError): string | null;
31
+ /**
32
+ * The server's project refusals as sentences. Returns the line, or null when
33
+ * the error is not one of them (the runner's generic handling is then the
34
+ * honest answer).
35
+ */
36
+ export declare function explainProjectRefusal(e: PlatformApiError, what: ProjectLookup): string | null;
37
+ export declare function registerProjectCommands<TClient extends ChassisClient<string>>(kit: CliKit<TClient>, program: Command, io: CliIo): void;
38
+ //# sourceMappingURL=projects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/commands/projects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,KAAK,aAAa,EAAmB,MAAM,yBAAyB,CAAC;AAUhG,OAAO,EAA8D,KAAK,KAAK,EAAE,MAAM,eAAe,CAAC;AACvG,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAkDxC;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAE/E;AAED;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GACvB,SAAS,GAAG,kBAAkB,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,cAAc,CAAC;AAExF;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,gBAAgB,GAAG,MAAM,GAAG,IAAI,CAE9D;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,gBAAgB,EAAE,IAAI,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CA+B7F;AAyCD,wBAAgB,uBAAuB,CAAC,OAAO,SAAS,aAAa,CAAC,MAAM,CAAC,EAC3E,GAAG,EAAE,MAAM,CAAC,OAAO,CAAC,EACpB,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,KAAK,GACR,IAAI,CA8RN"}
@@ -0,0 +1,386 @@
1
+ import { PlatformApiError } from '@antasphere/chassis-sdk';
2
+ import { CliApiRefusal, CliUsageError, drainPages, printJson, table } from '../context.js';
3
+ import { resolveTeam, teamName } from './teams.js';
4
+ /**
5
+ * The project commands: a project is a subgroup of the workspace with its own
6
+ * members and three roles (viewer < editor < manager). The chassis owns the
7
+ * concept, so these commands spell no tool and no resource — what a project
8
+ * HOLDS is the tool's own group's business.
9
+ *
10
+ * Every refusal the server has a code for is turned into a sentence here
11
+ * (`explainProjectRefusal`): the wire messages are correct but terse, and the
12
+ * tiered answer (404 for a project the caller cannot read, 403 for a proven
13
+ * reader who may not act, 409 for an archived one) only reads as an
14
+ * explanation once it says WHICH of the three happened. Anything else is
15
+ * rethrown and the runner prints it unchanged.
16
+ *
17
+ * `--json` is the API payload verbatim through `printJson` (the raw sink);
18
+ * every human line goes through the sanitizing sinks the runner installed —
19
+ * a project name, a description and a member's display name are all somebody
20
+ * else's text heading for a terminal.
21
+ */
22
+ const ROLES = ['viewer', 'editor', 'manager'];
23
+ /** `--role`, validated here so a typo is a usage error, never a 400. */
24
+ function parseRole(value) {
25
+ if (ROLES.includes(value))
26
+ return value;
27
+ throw new CliUsageError(`Unknown role "${value}" — one of ${ROLES.join(', ')}.`);
28
+ }
29
+ /** `--archived <false|true|all>`; `false` (the live projects) is the server's default. */
30
+ function parseArchivedFilter(value) {
31
+ if (value === 'false' || value === 'true' || value === 'all')
32
+ return value;
33
+ throw new CliUsageError(`Unknown --archived value "${value}" — one of false, true, all.`);
34
+ }
35
+ /** `--metadata <json>`: a JSON OBJECT, the opaque seam the contract defines. */
36
+ function parseMetadata(value) {
37
+ let parsed;
38
+ try {
39
+ parsed = JSON.parse(value);
40
+ }
41
+ catch {
42
+ throw new CliUsageError('--metadata takes a JSON object, and this did not parse as JSON.');
43
+ }
44
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
45
+ throw new CliUsageError('--metadata takes a JSON object (not an array, a string, or null).');
46
+ }
47
+ return parsed;
48
+ }
49
+ /**
50
+ * The membership argument: an `@` makes it an email, anything else a user id.
51
+ * Better Auth ids are opaque text, so there is no id shape to test for — but
52
+ * an email always carries the `@`, and a user id never may (the server reads
53
+ * exactly one of the two fields, so guessing wrong is a `member_not_found`
54
+ * rather than a silent mismatch).
55
+ */
56
+ export function memberRef(value) {
57
+ return value.includes('@') ? { email: value } : { userId: value };
58
+ }
59
+ /**
60
+ * The role an `insufficient_project_role` answer names (`This needs the
61
+ * editor role on the project`), or null when the wire says none: the one
62
+ * place the sentence is parsed, for the chassis verbs and a tool's own.
63
+ */
64
+ export function roleNamedBy(e) {
65
+ return /needs the (\w+) role/.exec(e.message)?.[1] ?? null;
66
+ }
67
+ /**
68
+ * The server's project refusals as sentences. Returns the line, or null when
69
+ * the error is not one of them (the runner's generic handling is then the
70
+ * honest answer).
71
+ */
72
+ export function explainProjectRefusal(e, what) {
73
+ switch (e.code) {
74
+ case 'not_found':
75
+ return 'No such project, or it is not yours to read. (A project you are not a member of answers the same way: its existence is not probeable.)';
76
+ case 'insufficient_project_role':
77
+ // The chassis routes all gate on `manager`; a tool's route may gate on
78
+ // `editor` (linking a resource). The wire sentence names the role.
79
+ return `You need the ${roleNamedBy(e) ?? 'manager'} role on this project to do that.`;
80
+ case 'guest_forbidden':
81
+ return 'You are a guest of this workspace, and guests do not take part in projects.';
82
+ case 'project_archived':
83
+ return 'This project is archived and read-only. Unarchive it first to change it.';
84
+ case 'project_not_archived':
85
+ return 'This project is not archived, so there is nothing to unarchive.';
86
+ case 'already_member':
87
+ return what === 'workspace-team'
88
+ ? 'That team is already a member of this project. Change its role with `members role --team` instead.'
89
+ : 'That person is already a member of this project. Change their role with `members role` instead.';
90
+ case 'team_not_found':
91
+ return what === 'project-team'
92
+ ? 'That team is not a member of this project.'
93
+ : 'No team of this workspace matches — check the slug or id.';
94
+ case 'member_not_found':
95
+ return what === 'workspace-member'
96
+ ? 'No active member of this workspace matches — check the user id or email. Only a member of the workspace can join a project.'
97
+ : 'That person is not a member of this project.';
98
+ case 'guest_target':
99
+ return 'That person is a guest of the workspace, and a guest cannot be a project member. Invite them as a workspace member first.';
100
+ default:
101
+ return null;
102
+ }
103
+ }
104
+ /** Run a project call, turning the known refusals into sentences. */
105
+ async function explained(what, run) {
106
+ try {
107
+ return await run();
108
+ }
109
+ catch (e) {
110
+ if (e instanceof PlatformApiError) {
111
+ const line = explainProjectRefusal(e, what);
112
+ if (line)
113
+ throw new CliApiRefusal(line, e.status);
114
+ }
115
+ throw e;
116
+ }
117
+ }
118
+ /** One project, as the human sees it. */
119
+ function projectLines(p) {
120
+ const metadataKeys = Object.keys(p.metadata);
121
+ return (`${p.name}${p.archivedAt ? ' [archived]' : ''}\n` +
122
+ ` id: ${p.id}\n` +
123
+ ` your role: ${p.myRole}\n` +
124
+ ` members: ${p.memberCount}\n` +
125
+ (p.description ? ` description: ${p.description}\n` : '') +
126
+ (metadataKeys.length > 0 ? ` metadata: ${metadataKeys.join(', ')}\n` : '') +
127
+ (p.archivedAt ? ` archived: ${p.archivedAt}\n` : '') +
128
+ ` created: ${p.createdAt}\n`);
129
+ }
130
+ /** `a manager`, `an editor`: the article a role takes. */
131
+ const article = (role) => (/^[aeiou]/i.test(role) ? 'an' : 'a');
132
+ /** One member, a person or a team, as the human sees it. */
133
+ function memberLine(m) {
134
+ if (m.kind === 'team') {
135
+ return `team ${teamName(m)} (${m.slug}) is ${article(m.role)} ${m.role} of this project for its ${m.membersCount} member${m.membersCount === 1 ? '' : 's'} (team ${m.teamId}).\n`;
136
+ }
137
+ return `${m.name} <${m.email}> is ${article(m.role)} ${m.role} of this project (user ${m.userId}).\n`;
138
+ }
139
+ export function registerProjectCommands(kit, program, io) {
140
+ const { requireApiKey, resolveContext } = kit;
141
+ const projects = program
142
+ .command('projects')
143
+ .description('Manage the projects of the workspace (subgroups with their own members)');
144
+ // ── projects list ─────────────────────────────────────────────────────────
145
+ projects
146
+ .command('list')
147
+ .description('List the projects you belong to (newest first, cursor-paginated)')
148
+ .option('--cursor <cursor>', 'resume from a previous nextCursor')
149
+ .option('--limit <n>', 'page size (1-100)', (v) => parseInt(v, 10))
150
+ .option('--all', 'follow nextCursor until every page is fetched', false)
151
+ .option('--archived <false|true|all>', 'which projects to list (default: false, the live ones)')
152
+ .action(async (opts, cmd) => {
153
+ const ctx = resolveContext(cmd, io);
154
+ await requireApiKey(ctx);
155
+ const params = {};
156
+ if (opts.cursor)
157
+ params.cursor = opts.cursor;
158
+ if (opts.limit !== undefined)
159
+ params.limit = opts.limit;
160
+ if (opts.archived !== undefined)
161
+ params.archived = parseArchivedFilter(opts.archived);
162
+ const first = await explained('project', () => ctx.client.projects(params));
163
+ const rows = opts.all
164
+ ? await drainPages({ rows: first.projects, nextCursor: first.nextCursor }, async (cursor) => {
165
+ const page = await explained('project', () => ctx.client.projects({ ...params, cursor }));
166
+ return { rows: page.projects, nextCursor: page.nextCursor };
167
+ })
168
+ : first.projects;
169
+ const nextCursor = opts.all ? null : first.nextCursor;
170
+ // The wire shape, so scripts can thread nextCursor (--all drains it to null).
171
+ if (ctx.json)
172
+ return printJson(io, { projects: rows, nextCursor });
173
+ if (rows.length === 0) {
174
+ io.out.write('No projects.\n');
175
+ return;
176
+ }
177
+ io.out.write(table(rows.map((p) => [
178
+ p.id,
179
+ p.myRole,
180
+ `${p.memberCount} member${p.memberCount === 1 ? '' : 's'}`,
181
+ `${p.name}${p.archivedAt ? ' [archived]' : ''}`
182
+ ])));
183
+ if (nextCursor) {
184
+ io.out.write(`More available: rerun with --cursor ${nextCursor} or --all\n`);
185
+ }
186
+ });
187
+ // ── projects get ──────────────────────────────────────────────────────────
188
+ projects
189
+ .command('get <id>')
190
+ .description('Show one project, with your own role on it')
191
+ .action(async (id, _opts, cmd) => {
192
+ const ctx = resolveContext(cmd, io);
193
+ await requireApiKey(ctx);
194
+ const project = await explained('project', () => ctx.client.project(id));
195
+ if (ctx.json)
196
+ return printJson(io, project);
197
+ io.out.write(projectLines(project));
198
+ });
199
+ // ── projects create ───────────────────────────────────────────────────────
200
+ projects
201
+ .command('create <name>')
202
+ .description('Create a project; you become its first manager')
203
+ .option('--description <text>', 'what the project is for')
204
+ .option('--metadata <json>', 'a JSON object of your own, opaque to the server')
205
+ .action(async (name, opts, cmd) => {
206
+ const ctx = resolveContext(cmd, io);
207
+ await requireApiKey(ctx);
208
+ const body = {
209
+ name,
210
+ ...(opts.description !== undefined ? { description: opts.description } : {}),
211
+ ...(opts.metadata !== undefined ? { metadata: parseMetadata(opts.metadata) } : {})
212
+ };
213
+ const project = await explained('project', () => ctx.client.createProject(body));
214
+ if (ctx.json)
215
+ return printJson(io, project);
216
+ io.out.write(`Created project "${project.name}".\n${projectLines(project)}`);
217
+ });
218
+ // ── projects update ───────────────────────────────────────────────────────
219
+ projects
220
+ .command('update <id>')
221
+ .description("Change a project's name, description or metadata (manager)")
222
+ .option('--name <name>', 'rename the project')
223
+ .option('--description <text>', 'replace the description')
224
+ .option('--clear-description', 'remove the description', false)
225
+ .option('--metadata <json>', 'replace the whole metadata object (a JSON object)')
226
+ .action(async (id, opts, cmd) => {
227
+ if (opts.description !== undefined && opts.clearDescription) {
228
+ throw new CliUsageError('Pass either --description <text> or --clear-description, not both.');
229
+ }
230
+ const patch = {
231
+ ...(opts.name !== undefined ? { name: opts.name } : {}),
232
+ ...(opts.clearDescription
233
+ ? { description: null }
234
+ : opts.description !== undefined
235
+ ? { description: opts.description }
236
+ : {}),
237
+ ...(opts.metadata !== undefined ? { metadata: parseMetadata(opts.metadata) } : {})
238
+ };
239
+ if (Object.keys(patch).length === 0) {
240
+ throw new CliUsageError('Nothing to change — pass --name, --description, --clear-description or --metadata.');
241
+ }
242
+ const ctx = resolveContext(cmd, io);
243
+ await requireApiKey(ctx);
244
+ const project = await explained('project', () => ctx.client.updateProject(id, patch));
245
+ if (ctx.json)
246
+ return printJson(io, project);
247
+ io.out.write(`Updated project "${project.name}".\n${projectLines(project)}`);
248
+ });
249
+ // ── projects archive / unarchive ──────────────────────────────────────────
250
+ projects
251
+ .command('archive <id>')
252
+ .description('Archive a project: out of the default list and read-only (manager). Never deleted')
253
+ .action(async (id, _opts, cmd) => {
254
+ const ctx = resolveContext(cmd, io);
255
+ await requireApiKey(ctx);
256
+ const project = await explained('project', () => ctx.client.archiveProject(id));
257
+ if (ctx.json)
258
+ return printJson(io, project);
259
+ io.out.write(`Archived "${project.name}". It is read-only and out of \`projects list\` until you unarchive it.\n`);
260
+ });
261
+ projects
262
+ .command('unarchive <id>')
263
+ .description('Bring an archived project back (manager)')
264
+ .action(async (id, _opts, cmd) => {
265
+ const ctx = resolveContext(cmd, io);
266
+ await requireApiKey(ctx);
267
+ const project = await explained('project', () => ctx.client.unarchiveProject(id));
268
+ if (ctx.json)
269
+ return printJson(io, project);
270
+ io.out.write(`Unarchived "${project.name}". It is writable again.\n`);
271
+ });
272
+ // ── projects members ──────────────────────────────────────────────────────
273
+ const members = projects.command('members').description("Manage a project's members");
274
+ members
275
+ .command('list <project>')
276
+ .description('List the members of a project')
277
+ .option('--cursor <cursor>', 'resume from a previous nextCursor')
278
+ .option('--limit <n>', 'page size (1-100)', (v) => parseInt(v, 10))
279
+ .option('--all', 'follow nextCursor until every page is fetched', false)
280
+ .action(async (project, opts, cmd) => {
281
+ const ctx = resolveContext(cmd, io);
282
+ await requireApiKey(ctx);
283
+ const params = {};
284
+ if (opts.cursor)
285
+ params.cursor = opts.cursor;
286
+ if (opts.limit !== undefined)
287
+ params.limit = opts.limit;
288
+ const first = await explained('project', () => ctx.client.projectMembers(project, params));
289
+ const rows = opts.all
290
+ ? await drainPages({ rows: first.members, nextCursor: first.nextCursor }, async (cursor) => {
291
+ const page = await explained('project', () => ctx.client.projectMembers(project, { ...params, cursor }));
292
+ return { rows: page.members, nextCursor: page.nextCursor };
293
+ })
294
+ : first.members;
295
+ const nextCursor = opts.all ? null : first.nextCursor;
296
+ if (ctx.json)
297
+ return printJson(io, { members: rows, nextCursor });
298
+ if (rows.length === 0) {
299
+ io.out.write('No members.\n');
300
+ return;
301
+ }
302
+ io.out.write(table(rows.map((m) => m.kind === 'team'
303
+ ? [
304
+ 'team',
305
+ m.slug,
306
+ m.role,
307
+ `${m.membersCount} member${m.membersCount === 1 ? '' : 's'}`,
308
+ teamName(m)
309
+ ]
310
+ : ['person', m.userId, m.role, m.email, m.name])));
311
+ if (nextCursor) {
312
+ io.out.write(`More available: rerun with --cursor ${nextCursor} or --all\n`);
313
+ }
314
+ });
315
+ members
316
+ .command('add <project> [userIdOrEmail]')
317
+ .description('Add a member of the workspace, or one of its teams with --team, to the project (manager)')
318
+ .requiredOption('--role <viewer|editor|manager>', 'the role they get on this project')
319
+ .option('--team <team>', 'add this team (a slug or an id) instead of a person: its members hold the role')
320
+ .action(async (project, who, opts, cmd) => {
321
+ if ((who === undefined) === (opts.team === undefined)) {
322
+ throw new CliUsageError('Name exactly one: a person (<userIdOrEmail>) or a team (--team <team>).');
323
+ }
324
+ const role = parseRole(opts.role);
325
+ const ctx = resolveContext(cmd, io);
326
+ await requireApiKey(ctx);
327
+ if (opts.team !== undefined) {
328
+ const team = await resolveTeam(ctx.client, opts.team);
329
+ const body = { teamId: team.id, role };
330
+ const entry = await explained('workspace-team', () => ctx.client.addProjectMember(project, body));
331
+ if (ctx.json)
332
+ return printJson(io, entry);
333
+ io.out.write(`Added ${memberLine(entry)}`);
334
+ return;
335
+ }
336
+ const body = { ...memberRef(who), role };
337
+ // `add` looks the person up across the WORKSPACE, so its
338
+ // `member_not_found` is about the workspace, not about the project.
339
+ const member = await explained('workspace-member', () => ctx.client.addProjectMember(project, body));
340
+ if (ctx.json)
341
+ return printJson(io, member);
342
+ io.out.write(`Added ${memberLine(member)}`);
343
+ });
344
+ members
345
+ .command('role <project> <userIdOrTeam> <role>')
346
+ .description("Change a member's role on the project, or a team's with --team (manager)")
347
+ .option('--team', 'the second argument names a team (a slug or an id), not a person', false)
348
+ .action(async (project, target, role, opts, cmd) => {
349
+ const parsed = parseRole(role);
350
+ const ctx = resolveContext(cmd, io);
351
+ await requireApiKey(ctx);
352
+ if (opts.team) {
353
+ const team = await resolveTeam(ctx.client, target);
354
+ const entry = await explained('project-team', () => ctx.client.setProjectTeamRole(project, team.id, parsed));
355
+ if (ctx.json)
356
+ return printJson(io, entry);
357
+ io.out.write(`Now ${memberLine(entry)}`);
358
+ return;
359
+ }
360
+ const member = await explained('project-member', () => ctx.client.setProjectMemberRole(project, target, parsed));
361
+ if (ctx.json)
362
+ return printJson(io, member);
363
+ io.out.write(`Now ${memberLine(member)}`);
364
+ });
365
+ members
366
+ .command('remove <project> <userIdOrTeam>')
367
+ .description('Remove a member from the project, or a team with --team (a manager removes anyone; anyone removes themselves)')
368
+ .option('--team', 'the second argument names a team (a slug or an id), not a person', false)
369
+ .action(async (project, target, opts, cmd) => {
370
+ const ctx = resolveContext(cmd, io);
371
+ await requireApiKey(ctx);
372
+ if (opts.team) {
373
+ const team = await resolveTeam(ctx.client, target);
374
+ const entry = await explained('project-team', () => ctx.client.removeProjectTeam(project, team.id));
375
+ if (ctx.json)
376
+ return printJson(io, entry);
377
+ io.out.write(`Removed team ${teamName(entry)} (${entry.slug}) from this project. Its people keep their own entries.\n`);
378
+ return;
379
+ }
380
+ const member = await explained('project-member', () => ctx.client.removeProjectMember(project, target));
381
+ if (ctx.json)
382
+ return printJson(io, member);
383
+ io.out.write(`Removed ${member.name} <${member.email}> from this project.\n`);
384
+ });
385
+ }
386
+ //# sourceMappingURL=projects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/commands/projects.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAuC,MAAM,yBAAyB,CAAC;AAUhG,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAc,MAAM,eAAe,CAAC;AAEvG,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEnD;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,KAAK,GAA2B,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;AAEtE,wEAAwE;AACxE,SAAS,SAAS,CAAC,KAAa;IAC9B,IAAK,KAA2B,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAoB,CAAC;IAC9E,MAAM,IAAI,aAAa,CAAC,iBAAiB,KAAK,cAAc,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACnF,CAAC;AAED,0FAA0F;AAC1F,SAAS,mBAAmB,CAAC,KAAa;IACxC,IAAI,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,KAAK;QAAE,OAAO,KAAK,CAAC;IAC3E,MAAM,IAAI,aAAa,CAAC,6BAA6B,KAAK,8BAA8B,CAAC,CAAC;AAC5F,CAAC;AAED,gFAAgF;AAChF,SAAS,aAAa,CAAC,KAAa;IAClC,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,aAAa,CAAC,iEAAiE,CAAC,CAAC;IAC7F,CAAC;IACD,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3E,MAAM,IAAI,aAAa,CAAC,mEAAmE,CAAC,CAAC;IAC/F,CAAC;IACD,OAAO,MAAiC,CAAC;AAC3C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,OAAO,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AACpE,CAAC;AAYD;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,CAAmB;IAC7C,OAAO,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AAC7D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,CAAmB,EAAE,IAAmB;IAC5E,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QACf,KAAK,WAAW;YACd,OAAO,wIAAwI,CAAC;QAClJ,KAAK,2BAA2B;YAC9B,uEAAuE;YACvE,mEAAmE;YACnE,OAAO,gBAAgB,WAAW,CAAC,CAAC,CAAC,IAAI,SAAS,mCAAmC,CAAC;QACxF,KAAK,iBAAiB;YACpB,OAAO,6EAA6E,CAAC;QACvF,KAAK,kBAAkB;YACrB,OAAO,0EAA0E,CAAC;QACpF,KAAK,sBAAsB;YACzB,OAAO,iEAAiE,CAAC;QAC3E,KAAK,gBAAgB;YACnB,OAAO,IAAI,KAAK,gBAAgB;gBAC9B,CAAC,CAAC,oGAAoG;gBACtG,CAAC,CAAC,iGAAiG,CAAC;QACxG,KAAK,gBAAgB;YACnB,OAAO,IAAI,KAAK,cAAc;gBAC5B,CAAC,CAAC,4CAA4C;gBAC9C,CAAC,CAAC,2DAA2D,CAAC;QAClE,KAAK,kBAAkB;YACrB,OAAO,IAAI,KAAK,kBAAkB;gBAChC,CAAC,CAAC,6HAA6H;gBAC/H,CAAC,CAAC,8CAA8C,CAAC;QACrD,KAAK,cAAc;YACjB,OAAO,2HAA2H,CAAC;QACrI;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC;AAED,qEAAqE;AACrE,KAAK,UAAU,SAAS,CAAI,IAAmB,EAAE,GAAqB;IACpE,IAAI,CAAC;QACH,OAAO,MAAM,GAAG,EAAE,CAAC;IACrB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,YAAY,gBAAgB,EAAE,CAAC;YAClC,MAAM,IAAI,GAAG,qBAAqB,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;YAC5C,IAAI,IAAI;gBAAE,MAAM,IAAI,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;QACpD,CAAC;QACD,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAED,yCAAyC;AACzC,SAAS,YAAY,CAAC,CAAU;IAC9B,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC7C,OAAO,CACL,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,IAAI;QAClD,kBAAkB,CAAC,CAAC,EAAE,IAAI;QAC1B,kBAAkB,CAAC,CAAC,MAAM,IAAI;QAC9B,kBAAkB,CAAC,CAAC,WAAW,IAAI;QACnC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1D,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,kBAAkB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9E,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,kBAAkB,CAAC,CAAC,SAAS,IAAI,CAClC,CAAC;AACJ,CAAC;AAED,0DAA0D;AAC1D,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAExE,4DAA4D;AAC5D,SAAS,UAAU,CAAC,CAAgB;IAClC,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO,QAAQ,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,QAAQ,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,4BAA4B,CAAC,CAAC,YAAY,UAAU,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,MAAM,MAAM,CAAC;IACpL,CAAC;IACD,OAAO,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,KAAK,QAAQ,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,0BAA0B,CAAC,CAAC,MAAM,MAAM,CAAC;AACxG,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,GAAoB,EACpB,OAAgB,EAChB,EAAS;IAET,MAAM,EAAE,aAAa,EAAE,cAAc,EAAE,GAAG,GAAG,CAAC;IAE9C,MAAM,QAAQ,GAAG,OAAO;SACrB,OAAO,CAAC,UAAU,CAAC;SACnB,WAAW,CAAC,yEAAyE,CAAC,CAAC;IAE1F,6EAA6E;IAC7E,QAAQ;SACL,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,kEAAkE,CAAC;SAC/E,MAAM,CAAC,mBAAmB,EAAE,mCAAmC,CAAC;SAChE,MAAM,CAAC,aAAa,EAAE,mBAAmB,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;SAC1E,MAAM,CAAC,OAAO,EAAE,+CAA+C,EAAE,KAAK,CAAC;SACvE,MAAM,CAAC,6BAA6B,EAAE,wDAAwD,CAAC;SAC/F,MAAM,CACL,KAAK,EAAE,IAA0E,EAAE,GAAY,EAAE,EAAE;QACjG,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACpC,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QACzB,MAAM,MAAM,GAAuD,EAAE,CAAC;QACtE,IAAI,IAAI,CAAC,MAAM;YAAE,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC7C,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;YAAE,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACxD,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS;YAAE,MAAM,CAAC,QAAQ,GAAG,mBAAmB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtF,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QAC5E,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG;YACnB,CAAC,CAAC,MAAM,UAAU,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;gBACxF,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;gBAC1F,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC;YAC9D,CAAC,CAAC;YACJ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;QACnB,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC;QACtD,8EAA8E;QAC9E,IAAI,GAAG,CAAC,IAAI;YAAE,OAAO,SAAS,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;QACnE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;YAC/B,OAAO;QACT,CAAC;QACD,EAAE,CAAC,GAAG,CAAC,KAAK,CACV,KAAK,CACH,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YACd,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,MAAM;YACR,GAAG,CAAC,CAAC,WAAW,UAAU,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE;YAC1D,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE;SACjD,CAAC,CACH,CACF,CAAC;QACF,IAAI,UAAU,EAAE,CAAC;YACf,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,uCAAuC,UAAU,aAAa,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC,CACF,CAAC;IAEJ,6EAA6E;IAC7E,QAAQ;SACL,OAAO,CAAC,UAAU,CAAC;SACnB,WAAW,CAAC,4CAA4C,CAAC;SACzD,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,KAAK,EAAE,GAAY,EAAE,EAAE;QAChD,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACpC,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QACzB,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;QACzE,IAAI,GAAG,CAAC,IAAI;YAAE,OAAO,SAAS,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC5C,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEL,6EAA6E;IAC7E,QAAQ;SACL,OAAO,CAAC,eAAe,CAAC;SACxB,WAAW,CAAC,gDAAgD,CAAC;SAC7D,MAAM,CAAC,sBAAsB,EAAE,yBAAyB,CAAC;SACzD,MAAM,CAAC,mBAAmB,EAAE,iDAAiD,CAAC;SAC9E,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,IAAiD,EAAE,GAAY,EAAE,EAAE;QAC9F,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACpC,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QACzB,MAAM,IAAI,GAAkB;YAC1B,IAAI;YACJ,GAAG,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5E,GAAG,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACnF,CAAC;QACF,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;QACjF,IAAI,GAAG,CAAC,IAAI;YAAE,OAAO,SAAS,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC5C,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,oBAAoB,OAAO,CAAC,IAAI,OAAO,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC/E,CAAC,CAAC,CAAC;IAEL,6EAA6E;IAC7E,QAAQ;SACL,OAAO,CAAC,aAAa,CAAC;SACtB,WAAW,CAAC,4DAA4D,CAAC;SACzE,MAAM,CAAC,eAAe,EAAE,oBAAoB,CAAC;SAC7C,MAAM,CAAC,sBAAsB,EAAE,yBAAyB,CAAC;SACzD,MAAM,CAAC,qBAAqB,EAAE,wBAAwB,EAAE,KAAK,CAAC;SAC9D,MAAM,CAAC,mBAAmB,EAAE,mDAAmD,CAAC;SAChF,MAAM,CACL,KAAK,EACH,EAAU,EACV,IAKC,EACD,GAAY,EACZ,EAAE;QACF,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC5D,MAAM,IAAI,aAAa,CAAC,oEAAoE,CAAC,CAAC;QAChG,CAAC;QACD,MAAM,KAAK,GAAkB;YAC3B,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvD,GAAG,CAAC,IAAI,CAAC,gBAAgB;gBACvB,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE;gBACvB,CAAC,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS;oBAC9B,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE;oBACnC,CAAC,CAAC,EAAE,CAAC;YACT,GAAG,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAClE,CAAC;QACnB,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,aAAa,CACrB,oFAAoF,CACrF,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACpC,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QACzB,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC;QACtF,IAAI,GAAG,CAAC,IAAI;YAAE,OAAO,SAAS,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC5C,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,oBAAoB,OAAO,CAAC,IAAI,OAAO,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC/E,CAAC,CACF,CAAC;IAEJ,6EAA6E;IAC7E,QAAQ;SACL,OAAO,CAAC,cAAc,CAAC;SACvB,WAAW,CAAC,mFAAmF,CAAC;SAChG,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,KAAK,EAAE,GAAY,EAAE,EAAE;QAChD,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACpC,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QACzB,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC;QAChF,IAAI,GAAG,CAAC,IAAI;YAAE,OAAO,SAAS,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC5C,EAAE,CAAC,GAAG,CAAC,KAAK,CACV,aAAa,OAAO,CAAC,IAAI,2EAA2E,CACrG,CAAC;IACJ,CAAC,CAAC,CAAC;IAEL,QAAQ;SACL,OAAO,CAAC,gBAAgB,CAAC;SACzB,WAAW,CAAC,0CAA0C,CAAC;SACvD,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,KAAK,EAAE,GAAY,EAAE,EAAE;QAChD,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACpC,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QACzB,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC;QAClF,IAAI,GAAG,CAAC,IAAI;YAAE,OAAO,SAAS,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC5C,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,eAAe,OAAO,CAAC,IAAI,4BAA4B,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEL,6EAA6E;IAC7E,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,4BAA4B,CAAC,CAAC;IAEtF,OAAO;SACJ,OAAO,CAAC,gBAAgB,CAAC;SACzB,WAAW,CAAC,+BAA+B,CAAC;SAC5C,MAAM,CAAC,mBAAmB,EAAE,mCAAmC,CAAC;SAChE,MAAM,CAAC,aAAa,EAAE,mBAAmB,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;SAC1E,MAAM,CAAC,OAAO,EAAE,+CAA+C,EAAE,KAAK,CAAC;SACvE,MAAM,CACL,KAAK,EAAE,OAAe,EAAE,IAAuD,EAAE,GAAY,EAAE,EAAE;QAC/F,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACpC,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QACzB,MAAM,MAAM,GAAe,EAAE,CAAC;QAC9B,IAAI,IAAI,CAAC,MAAM;YAAE,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC7C,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;YAAE,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACxD,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QAC3F,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG;YACnB,CAAC,CAAC,MAAM,UAAU,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;gBACvF,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,SAAS,EAAE,GAAG,EAAE,CAC3C,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,CAAC,CAC1D,CAAC;gBACF,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC;YAC7D,CAAC,CAAC;YACJ,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;QAClB,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC;QACtD,IAAI,GAAG,CAAC,IAAI;YAAE,OAAO,SAAS,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;QAClE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;YAC9B,OAAO;QACT,CAAC;QACD,EAAE,CAAC,GAAG,CAAC,KAAK,CACV,KAAK,CACH,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACb,CAAC,CAAC,IAAI,KAAK,MAAM;YACf,CAAC,CAAC;gBACE,MAAM;gBACN,CAAC,CAAC,IAAI;gBACN,CAAC,CAAC,IAAI;gBACN,GAAG,CAAC,CAAC,YAAY,UAAU,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE;gBAC5D,QAAQ,CAAC,CAAC,CAAC;aACZ;YACH,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAClD,CACF,CACF,CAAC;QACF,IAAI,UAAU,EAAE,CAAC;YACf,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,uCAAuC,UAAU,aAAa,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC,CACF,CAAC;IAEJ,OAAO;SACJ,OAAO,CAAC,+BAA+B,CAAC;SACxC,WAAW,CAAC,0FAA0F,CAAC;SACvG,cAAc,CAAC,gCAAgC,EAAE,mCAAmC,CAAC;SACrF,MAAM,CAAC,eAAe,EAAE,gFAAgF,CAAC;SACzG,MAAM,CACL,KAAK,EACH,OAAe,EACf,GAAuB,EACvB,IAAqC,EACrC,GAAY,EACZ,EAAE;QACF,IAAI,CAAC,GAAG,KAAK,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,EAAE,CAAC;YACtD,MAAM,IAAI,aAAa,CAAC,yEAAyE,CAAC,CAAC;QACrG,CAAC;QACD,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACpC,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;YACtD,MAAM,IAAI,GAAqB,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC;YACzD,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,gBAAgB,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;YAClG,IAAI,GAAG,CAAC,IAAI;gBAAE,OAAO,SAAS,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAC1C,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAC3C,OAAO;QACT,CAAC;QACD,MAAM,IAAI,GAAqB,EAAE,GAAG,SAAS,CAAC,GAAI,CAAC,EAAE,IAAI,EAAE,CAAC;QAC5D,yDAAyD;QACzD,oEAAoE;QACpE,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;QACrG,IAAI,GAAG,CAAC,IAAI;YAAE,OAAO,SAAS,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QAC3C,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC9C,CAAC,CACF,CAAC;IAEJ,OAAO;SACJ,OAAO,CAAC,sCAAsC,CAAC;SAC/C,WAAW,CAAC,0EAA0E,CAAC;SACvF,MAAM,CAAC,QAAQ,EAAE,kEAAkE,EAAE,KAAK,CAAC;SAC3F,MAAM,CAAC,KAAK,EAAE,OAAe,EAAE,MAAc,EAAE,IAAY,EAAE,IAAuB,EAAE,GAAY,EAAE,EAAE;QACrG,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACpC,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACnD,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,cAAc,EAAE,GAAG,EAAE,CACjD,GAAG,CAAC,MAAM,CAAC,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC,CACxD,CAAC;YACF,IAAI,GAAG,CAAC,IAAI;gBAAE,OAAO,SAAS,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAC1C,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACzC,OAAO;QACT,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,gBAAgB,EAAE,GAAG,EAAE,CACpD,GAAG,CAAC,MAAM,CAAC,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CACzD,CAAC;QACF,IAAI,GAAG,CAAC,IAAI;YAAE,OAAO,SAAS,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QAC3C,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,iCAAiC,CAAC;SAC1C,WAAW,CACV,+GAA+G,CAChH;SACA,MAAM,CAAC,QAAQ,EAAE,kEAAkE,EAAE,KAAK,CAAC;SAC3F,MAAM,CAAC,KAAK,EAAE,OAAe,EAAE,MAAc,EAAE,IAAuB,EAAE,GAAY,EAAE,EAAE;QACvF,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACpC,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACnD,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,cAAc,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,iBAAiB,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YACpG,IAAI,GAAG,CAAC,IAAI;gBAAE,OAAO,SAAS,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAC1C,EAAE,CAAC,GAAG,CAAC,KAAK,CACV,gBAAgB,QAAQ,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,IAAI,2DAA2D,CAC1G,CAAC;YACF,OAAO;QACT,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,gBAAgB,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QACxG,IAAI,GAAG,CAAC,IAAI;YAAE,OAAO,SAAS,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QAC3C,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,KAAK,wBAAwB,CAAC,CAAC;IAChF,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,46 @@
1
+ import type { Command } from 'commander';
2
+ import { PlatformApiError, type ChassisClient } from '@antasphere/chassis-sdk';
3
+ import type { Team } from '@antasphere/chassis-contract';
4
+ import { type CliIo } from '../context.js';
5
+ import type { CliKit } from '../kit.js';
6
+ /**
7
+ * The team commands: a team is a named group of the workspace's own members,
8
+ * on both editions. Every non-guest member reads the teams and their members;
9
+ * an owner or an admin creates, renames and deletes them and seats people.
10
+ * In a workspace the Antasphere account site manages, the teams are its
11
+ * projection: read here, every write refused with `hub_managed` and the page
12
+ * where they are managed. The family mirrors the hub's `antasphere teams`
13
+ * with this chassis's conventions: `<team>` is a slug or an id, every human
14
+ * line goes through the sanitizing sinks the runner installed (a team name is
15
+ * somebody else's text), and `--json` is the API payload verbatim.
16
+ */
17
+ /** What a `member_not_found` was about: the workspace (`add`) or the team (`remove`). */
18
+ export type TeamLookup = 'team' | 'workspace-member' | 'team-member';
19
+ /** The refusal context only the command knows: the slug it passed, the person it named. */
20
+ export interface TeamRefusalContext {
21
+ lookup: TeamLookup;
22
+ /** The slug the caller passed; absent, the server derived it from the name. */
23
+ slug?: string | undefined;
24
+ /** The person the caller named, for `already_member`. */
25
+ who?: string | undefined;
26
+ }
27
+ /**
28
+ * The server's team refusals as sentences. Returns the line, or null when the
29
+ * error is not one of them (the runner's generic handling is then the honest
30
+ * answer).
31
+ */
32
+ export declare function explainTeamRefusal(e: PlatformApiError, ctx: TeamRefusalContext): string | null;
33
+ /** Run a team call, turning the known refusals into sentences. */
34
+ export declare function explainedTeam<T>(ctx: TeamRefusalContext, run: () => Promise<T>): Promise<T>;
35
+ /** Every team of the workspace, page after page. */
36
+ export declare function allTeams(client: ChassisClient<string>): Promise<Team[]>;
37
+ /**
38
+ * A team named by its slug or its id (the hub's `findTeam`). An id is read
39
+ * directly; a slug, or an id the server does not know (a slug may look like
40
+ * one), is looked up in the workspace's list, by slug first, then by id.
41
+ */
42
+ export declare function resolveTeam(client: ChassisClient<string>, ref: string): Promise<Team>;
43
+ /** A team's name, marked when the Antasphere account site owns it. */
44
+ export declare function teamName(t: Pick<Team, 'name' | 'hubTeamId'>): string;
45
+ export declare function registerTeamCommands<TClient extends ChassisClient<string>>(kit: CliKit<TClient>, program: Command, io: CliIo): void;
46
+ //# sourceMappingURL=teams.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"teams.d.ts","sourceRoot":"","sources":["../../src/commands/teams.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,KAAK,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC/E,OAAO,KAAK,EAAE,IAAI,EAAkB,MAAM,8BAA8B,CAAC;AACzE,OAAO,EAA8D,KAAK,KAAK,EAAE,MAAM,eAAe,CAAC;AACvG,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAExC;;;;;;;;;;GAUG;AAEH,yFAAyF;AACzF,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,kBAAkB,GAAG,aAAa,CAAC;AAErE,2FAA2F;AAC3F,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,UAAU,CAAC;IACnB,+EAA+E;IAC/E,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,yDAAyD;IACzD,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,gBAAgB,EAAE,GAAG,EAAE,kBAAkB,GAAG,MAAM,GAAG,IAAI,CA2B9F;AAED,kEAAkE;AAClE,wBAAsB,aAAa,CAAC,CAAC,EAAE,GAAG,EAAE,kBAAkB,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAUjG;AAED,oDAAoD;AACpD,wBAAsB,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAM7E;AAID;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAc3F;AAYD,sEAAsE;AACtE,wBAAgB,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC,GAAG,MAAM,CAEpE;AAwBD,wBAAgB,oBAAoB,CAAC,OAAO,SAAS,aAAa,CAAC,MAAM,CAAC,EACxE,GAAG,EAAE,MAAM,CAAC,OAAO,CAAC,EACpB,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,KAAK,GACR,IAAI,CAyKN"}