checkbox-cli 3.1.0 → 3.2.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/checkbox.js +93 -33
- package/package.json +1 -1
package/dist/checkbox.js
CHANGED
|
@@ -16,7 +16,7 @@ import { join } from 'path';
|
|
|
16
16
|
// ── Config ──────────────────────────────────────────────────────────
|
|
17
17
|
const CONFIG_DIR = join(homedir(), '.checkbox');
|
|
18
18
|
const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
|
|
19
|
-
const VERSION = '3.
|
|
19
|
+
const VERSION = '3.2.0';
|
|
20
20
|
function loadConfig() {
|
|
21
21
|
try {
|
|
22
22
|
if (!existsSync(CONFIG_FILE))
|
|
@@ -194,6 +194,37 @@ async function pickEntity(post, orgId, entityType, label, filters) {
|
|
|
194
194
|
return null;
|
|
195
195
|
}
|
|
196
196
|
}
|
|
197
|
+
async function pickMember(post, orgId, label = 'team members') {
|
|
198
|
+
const s = p.spinner();
|
|
199
|
+
s.start(`Loading ${label}...`);
|
|
200
|
+
try {
|
|
201
|
+
const members = await listEntities(post, orgId, 'member');
|
|
202
|
+
s.stop(`${members.length} ${label}`);
|
|
203
|
+
if (members.length === 0) {
|
|
204
|
+
p.log.info(`No ${label} found.`);
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
const selected = await p.select({
|
|
208
|
+
message: `Choose a person`,
|
|
209
|
+
options: [
|
|
210
|
+
...members.slice(0, 50).map((m) => ({
|
|
211
|
+
value: m.id,
|
|
212
|
+
label: m.name || m.metadata?.email || 'Unknown',
|
|
213
|
+
hint: m.metadata?.role || '',
|
|
214
|
+
})),
|
|
215
|
+
{ value: '__back', label: pc.dim('\u2190 Back') },
|
|
216
|
+
],
|
|
217
|
+
});
|
|
218
|
+
if (p.isCancel(selected) || selected === '__back')
|
|
219
|
+
return null;
|
|
220
|
+
return members.find((m) => m.id === selected) || null;
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
s.stop(pc.red('Failed'));
|
|
224
|
+
p.log.error(err.message || `Could not load ${label}`);
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
197
228
|
async function txt(message, required = false, placeholder) {
|
|
198
229
|
const val = await p.text({
|
|
199
230
|
message,
|
|
@@ -527,12 +558,10 @@ async function mTasks(cfg, post) {
|
|
|
527
558
|
// Assignment
|
|
528
559
|
const assign = await yn('Assign to a specific person?');
|
|
529
560
|
if (assign) {
|
|
530
|
-
const
|
|
531
|
-
if (
|
|
532
|
-
payload.assigned_to =
|
|
533
|
-
|
|
534
|
-
if (assignName)
|
|
535
|
-
payload.assigned_to_name = assignName;
|
|
561
|
+
const member = await pickMember(post, cfg.orgId);
|
|
562
|
+
if (member) {
|
|
563
|
+
payload.assigned_to = member.id;
|
|
564
|
+
payload.assigned_to_name = member.name;
|
|
536
565
|
}
|
|
537
566
|
}
|
|
538
567
|
// Privacy
|
|
@@ -620,9 +649,18 @@ async function mTasks(cfg, post) {
|
|
|
620
649
|
// Share with specific users
|
|
621
650
|
const share = await yn('Share with specific users?');
|
|
622
651
|
if (share) {
|
|
623
|
-
const
|
|
624
|
-
|
|
625
|
-
|
|
652
|
+
const shareIds = [];
|
|
653
|
+
let addMore = true;
|
|
654
|
+
while (addMore) {
|
|
655
|
+
const member = await pickMember(post, cfg.orgId);
|
|
656
|
+
if (member)
|
|
657
|
+
shareIds.push(member.id);
|
|
658
|
+
else
|
|
659
|
+
break;
|
|
660
|
+
addMore = !!(await yn('Add another person?'));
|
|
661
|
+
}
|
|
662
|
+
if (shareIds.length > 0)
|
|
663
|
+
payload.shared_with_ids = shareIds;
|
|
626
664
|
}
|
|
627
665
|
await cmd(post, cfg.orgId, 'create_task', payload, 'Creating task...');
|
|
628
666
|
return mTasks(cfg, post);
|
|
@@ -693,12 +731,17 @@ async function mTasks(cfg, post) {
|
|
|
693
731
|
break;
|
|
694
732
|
}
|
|
695
733
|
case 'assigned_to': {
|
|
696
|
-
const
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
updates.assigned_to_name =
|
|
734
|
+
const unassign = await yn('Assign to someone? (No to unassign)');
|
|
735
|
+
if (unassign) {
|
|
736
|
+
const member = await pickMember(post, cfg.orgId);
|
|
737
|
+
if (member) {
|
|
738
|
+
updates.assigned_to = member.id;
|
|
739
|
+
updates.assigned_to_name = member.name;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
else {
|
|
743
|
+
updates.assigned_to = null;
|
|
744
|
+
updates.assigned_to_name = null;
|
|
702
745
|
}
|
|
703
746
|
break;
|
|
704
747
|
}
|
|
@@ -844,9 +887,9 @@ async function mTasks(cfg, post) {
|
|
|
844
887
|
const payload = { task_id: t.id };
|
|
845
888
|
const specify = await yn('Specify an approver?');
|
|
846
889
|
if (specify) {
|
|
847
|
-
const
|
|
848
|
-
if (
|
|
849
|
-
payload.approver_id =
|
|
890
|
+
const member = await pickMember(post, cfg.orgId);
|
|
891
|
+
if (member)
|
|
892
|
+
payload.approver_id = member.id;
|
|
850
893
|
}
|
|
851
894
|
await cmd(post, cfg.orgId, 'request_approval', payload, 'Requesting approval...');
|
|
852
895
|
return mTasks(cfg, post);
|
|
@@ -866,9 +909,9 @@ async function mTasks(cfg, post) {
|
|
|
866
909
|
const t = await pickEntity(post, cfg.orgId, 'task', 'tasks');
|
|
867
910
|
if (!t)
|
|
868
911
|
return mTasks(cfg, post);
|
|
869
|
-
const
|
|
870
|
-
if (
|
|
871
|
-
await cmd(post, cfg.orgId, 'send_nudge', { task_id: t.id, receiver_id:
|
|
912
|
+
const member = await pickMember(post, cfg.orgId);
|
|
913
|
+
if (member)
|
|
914
|
+
await cmd(post, cfg.orgId, 'send_nudge', { task_id: t.id, receiver_id: member.id }, `Sending reminder to ${member.name}...`);
|
|
872
915
|
return mTasks(cfg, post);
|
|
873
916
|
}
|
|
874
917
|
case 'corrective': {
|
|
@@ -1935,9 +1978,9 @@ async function mAutomation(cfg, post) {
|
|
|
1935
1978
|
condition.approval_approver_role = role;
|
|
1936
1979
|
}
|
|
1937
1980
|
else if (approverType === 'user') {
|
|
1938
|
-
const
|
|
1939
|
-
if (
|
|
1940
|
-
condition.approval_approver_id =
|
|
1981
|
+
const member = await pickMember(post, cfg.orgId);
|
|
1982
|
+
if (member)
|
|
1983
|
+
condition.approval_approver_id = member.id;
|
|
1941
1984
|
}
|
|
1942
1985
|
}
|
|
1943
1986
|
else if (ruleType === 'time_window') {
|
|
@@ -2506,6 +2549,7 @@ async function mApprovals(cfg, post) {
|
|
|
2506
2549
|
// ══════════════════════════════════════════════════════════════════════
|
|
2507
2550
|
async function mTeam(cfg, post) {
|
|
2508
2551
|
const a = await sel('Team', [
|
|
2552
|
+
{ value: 'list', label: 'View team members' },
|
|
2509
2553
|
{ value: 'invite', label: 'Invite a member' },
|
|
2510
2554
|
{ value: 'revoke', label: 'Revoke an invitation' },
|
|
2511
2555
|
{ value: 'role', label: 'Change a member\u2019s role' },
|
|
@@ -2515,6 +2559,22 @@ async function mTeam(cfg, post) {
|
|
|
2515
2559
|
if (!a || a === '__back')
|
|
2516
2560
|
return interactiveMenu(cfg);
|
|
2517
2561
|
switch (a) {
|
|
2562
|
+
case 'list': {
|
|
2563
|
+
const s = p.spinner();
|
|
2564
|
+
s.start('Loading team members...');
|
|
2565
|
+
const members = await listEntities(post, cfg.orgId, 'member');
|
|
2566
|
+
s.stop(`${members.length} team members`);
|
|
2567
|
+
if (members.length > 0) {
|
|
2568
|
+
const lines = members.map((m) => {
|
|
2569
|
+
const name = m.name || 'Unknown';
|
|
2570
|
+
const email = m.metadata?.email || '';
|
|
2571
|
+
const role = m.metadata?.role || '';
|
|
2572
|
+
return ` ${pc.cyan(pad(truncate(name, 30), 32))} ${pc.dim(pad(email, 30))} ${pc.dim(role)}`;
|
|
2573
|
+
});
|
|
2574
|
+
p.note(lines.join('\n'), 'Team Members');
|
|
2575
|
+
}
|
|
2576
|
+
return mTeam(cfg, post);
|
|
2577
|
+
}
|
|
2518
2578
|
case 'invite': {
|
|
2519
2579
|
const email = await txt('Email address', true);
|
|
2520
2580
|
if (!email)
|
|
@@ -2537,26 +2597,26 @@ async function mTeam(cfg, post) {
|
|
|
2537
2597
|
return mTeam(cfg, post);
|
|
2538
2598
|
}
|
|
2539
2599
|
case 'role': {
|
|
2540
|
-
const
|
|
2541
|
-
if (!
|
|
2600
|
+
const member = await pickMember(post, cfg.orgId);
|
|
2601
|
+
if (!member)
|
|
2542
2602
|
return mTeam(cfg, post);
|
|
2543
|
-
const role = await sel(
|
|
2603
|
+
const role = await sel(`New role for ${member.name}`, [
|
|
2544
2604
|
{ value: 'user', label: 'Member' },
|
|
2545
2605
|
{ value: 'admin', label: 'Admin' },
|
|
2546
2606
|
{ value: 'super_admin', label: 'Owner' },
|
|
2547
2607
|
]);
|
|
2548
2608
|
if (!role)
|
|
2549
2609
|
return mTeam(cfg, post);
|
|
2550
|
-
await cmd(post, cfg.orgId, 'update_member_role', { user_id:
|
|
2610
|
+
await cmd(post, cfg.orgId, 'update_member_role', { user_id: member.id, role }, `Updating ${member.name}'s role...`);
|
|
2551
2611
|
return mTeam(cfg, post);
|
|
2552
2612
|
}
|
|
2553
2613
|
case 'remove': {
|
|
2554
|
-
const
|
|
2555
|
-
if (!
|
|
2614
|
+
const member = await pickMember(post, cfg.orgId);
|
|
2615
|
+
if (!member)
|
|
2556
2616
|
return mTeam(cfg, post);
|
|
2557
|
-
const sure = await yn(
|
|
2617
|
+
const sure = await yn(`Remove ${member.name}? They will lose access to the workspace.`);
|
|
2558
2618
|
if (sure)
|
|
2559
|
-
await cmd(post, cfg.orgId, 'remove_member', { user_id:
|
|
2619
|
+
await cmd(post, cfg.orgId, 'remove_member', { user_id: member.id }, `Removing ${member.name}...`);
|
|
2560
2620
|
return mTeam(cfg, post);
|
|
2561
2621
|
}
|
|
2562
2622
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "checkbox-cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "Beautiful, interactive CLI for Checkbox compliance management. Setup wizard, guided workflows, and full workspace control from your terminal.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/checkbox.js",
|