@klevar/portal-cli 0.1.19 → 0.1.21

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.
@@ -28,6 +28,12 @@ export declare const CLI_EXEMPTIONS: readonly [{
28
28
  readonly reason: "Inbound webhook consumer called by Klevar Docs, not by operators or clients.";
29
29
  readonly owner: "Klevar Docs";
30
30
  readonly trackedAs: "Phase 17 inbound-webhook exemption";
31
+ }, {
32
+ readonly method: "GET";
33
+ readonly path: "/api/portal/projects/:id/timeline";
34
+ readonly reason: "Client-facing timeline used by the portal project UI; admin/operator timeline CLI already covers recall workflows.";
35
+ readonly owner: "Klevar Portal";
36
+ readonly trackedAs: "Phase 17 client timeline portal-ui exemption";
31
37
  }, {
32
38
  readonly method: "GET";
33
39
  readonly path: "/api/portal/projects/:projectId/recurring-checkpoints";
@@ -34,6 +34,13 @@ export const CLI_EXEMPTIONS = [
34
34
  owner: 'Klevar Docs',
35
35
  trackedAs: 'Phase 17 inbound-webhook exemption',
36
36
  },
37
+ {
38
+ method: 'GET',
39
+ path: '/api/portal/projects/:id/timeline',
40
+ reason: 'Client-facing timeline used by the portal project UI; admin/operator timeline CLI already covers recall workflows.',
41
+ owner: 'Klevar Portal',
42
+ trackedAs: 'Phase 17 client timeline portal-ui exemption',
43
+ },
37
44
  {
38
45
  method: 'GET',
39
46
  path: '/api/portal/projects/:projectId/recurring-checkpoints',
@@ -1 +1 @@
1
- {"version":3,"file":"_exemptions.js","sourceRoot":"","sources":["../../commands/_exemptions.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B;QACE,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,kBAAkB;QACxB,MAAM,EAAE,uEAAuE;QAC/E,KAAK,EAAE,eAAe;QACtB,SAAS,EAAE,yCAAyC;KACrD;IACD;QACE,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,mBAAmB;QACzB,MAAM,EAAE,uEAAuE;QAC/E,KAAK,EAAE,eAAe;QACtB,SAAS,EAAE,yCAAyC;KACrD;IACD;QACE,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,eAAe;QACrB,MAAM,EAAE,0GAA0G;QAClH,KAAK,EAAE,eAAe;QACtB,SAAS,EAAE,yCAAyC;KACrD;IACD;QACE,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,uBAAuB;QAC7B,MAAM,EAAE,yGAAyG;QACjH,KAAK,EAAE,eAAe;QACtB,SAAS,EAAE,qCAAqC;KACjD;IACD;QACE,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,qCAAqC;QAC3C,MAAM,EAAE,8EAA8E;QACtF,KAAK,EAAE,aAAa;QACpB,SAAS,EAAE,oCAAoC;KAChD;IACD;QACE,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,uDAAuD;QAC7D,MAAM,EAAE,qFAAqF;QAC7F,KAAK,EAAE,eAAe;QACtB,SAAS,EAAE,wCAAwC;KACpD;IACD;QACE,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,uDAAuD;QAC7D,MAAM,EAAE,uFAAuF;QAC/F,KAAK,EAAE,eAAe;QACtB,SAAS,EAAE,wCAAwC;KACpD;IACD;QACE,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,8CAA8C;QACpD,MAAM,EAAE,wDAAwD;QAChE,KAAK,EAAE,eAAe;QACtB,SAAS,EAAE,wCAAwC;KACpD;IACD;QACE,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,8CAA8C;QACpD,MAAM,EAAE,uDAAuD;QAC/D,KAAK,EAAE,eAAe;QACtB,SAAS,EAAE,wCAAwC;KACpD;IACD;QACE,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,mDAAmD;QACzD,MAAM,EAAE,yDAAyD;QACjE,KAAK,EAAE,eAAe;QACtB,SAAS,EAAE,wCAAwC;KACpD;CACO,CAAC"}
1
+ {"version":3,"file":"_exemptions.js","sourceRoot":"","sources":["../../commands/_exemptions.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B;QACE,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,kBAAkB;QACxB,MAAM,EAAE,uEAAuE;QAC/E,KAAK,EAAE,eAAe;QACtB,SAAS,EAAE,yCAAyC;KACrD;IACD;QACE,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,mBAAmB;QACzB,MAAM,EAAE,uEAAuE;QAC/E,KAAK,EAAE,eAAe;QACtB,SAAS,EAAE,yCAAyC;KACrD;IACD;QACE,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,eAAe;QACrB,MAAM,EAAE,0GAA0G;QAClH,KAAK,EAAE,eAAe;QACtB,SAAS,EAAE,yCAAyC;KACrD;IACD;QACE,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,uBAAuB;QAC7B,MAAM,EAAE,yGAAyG;QACjH,KAAK,EAAE,eAAe;QACtB,SAAS,EAAE,qCAAqC;KACjD;IACD;QACE,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,qCAAqC;QAC3C,MAAM,EAAE,8EAA8E;QACtF,KAAK,EAAE,aAAa;QACpB,SAAS,EAAE,oCAAoC;KAChD;IACD;QACE,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,mCAAmC;QACzC,MAAM,EAAE,oHAAoH;QAC5H,KAAK,EAAE,eAAe;QACtB,SAAS,EAAE,8CAA8C;KAC1D;IACD;QACE,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,uDAAuD;QAC7D,MAAM,EAAE,qFAAqF;QAC7F,KAAK,EAAE,eAAe;QACtB,SAAS,EAAE,wCAAwC;KACpD;IACD;QACE,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,uDAAuD;QAC7D,MAAM,EAAE,uFAAuF;QAC/F,KAAK,EAAE,eAAe;QACtB,SAAS,EAAE,wCAAwC;KACpD;IACD;QACE,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,8CAA8C;QACpD,MAAM,EAAE,wDAAwD;QAChE,KAAK,EAAE,eAAe;QACtB,SAAS,EAAE,wCAAwC;KACpD;IACD;QACE,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,8CAA8C;QACpD,MAAM,EAAE,uDAAuD;QAC/D,KAAK,EAAE,eAAe;QACtB,SAAS,EAAE,wCAAwC;KACpD;IACD;QACE,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,mDAAmD;QACzD,MAAM,EAAE,yDAAyD;QACjE,KAAK,EAAE,eAAe;QACtB,SAAS,EAAE,wCAAwC;KACpD;CACO,CAAC"}
@@ -522,6 +522,143 @@ export declare const COMMAND_GROUPS: {
522
522
  description: string;
523
523
  };
524
524
  };
525
+ operator: {
526
+ inbox: {
527
+ method: "GET";
528
+ path: string;
529
+ auth: "apiKey";
530
+ description: string;
531
+ queryParams: string[];
532
+ };
533
+ 'inbox.mark-read': {
534
+ method: "POST";
535
+ path: string;
536
+ auth: "apiKey";
537
+ description: string;
538
+ };
539
+ 'inbox.mark-client-read': {
540
+ method: "POST";
541
+ path: string;
542
+ auth: "apiKey";
543
+ description: string;
544
+ };
545
+ 'inbox.mark-project-read': {
546
+ method: "POST";
547
+ path: string;
548
+ auth: "apiKey";
549
+ description: string;
550
+ };
551
+ 'inbox.mark-all-read': {
552
+ method: "POST";
553
+ path: string;
554
+ auth: "apiKey";
555
+ description: string;
556
+ };
557
+ 'reports.monthly': {
558
+ method: "GET";
559
+ path: string;
560
+ auth: "apiKey";
561
+ description: string;
562
+ queryParams: string[];
563
+ };
564
+ 'client.timeline': {
565
+ method: "GET";
566
+ path: string;
567
+ auth: "apiKey";
568
+ description: string;
569
+ queryParams: string[];
570
+ };
571
+ 'project.timeline': {
572
+ method: "GET";
573
+ path: string;
574
+ auth: "apiKey";
575
+ description: string;
576
+ queryParams: string[];
577
+ };
578
+ 'ops-health': {
579
+ method: "GET";
580
+ path: string;
581
+ auth: "apiKey";
582
+ description: string;
583
+ };
584
+ 'smoke.portal': {
585
+ method: "GET";
586
+ path: string;
587
+ auth: "apiKey";
588
+ description: string;
589
+ };
590
+ 'smoke.docs': {
591
+ method: "GET";
592
+ path: string;
593
+ auth: "apiKey";
594
+ description: string;
595
+ };
596
+ 'smoke.capacity': {
597
+ method: "GET";
598
+ path: string;
599
+ auth: "apiKey";
600
+ description: string;
601
+ };
602
+ 'smoke.recurring': {
603
+ method: "GET";
604
+ path: string;
605
+ auth: "apiKey";
606
+ description: string;
607
+ };
608
+ 'smoke.notifications': {
609
+ method: "GET";
610
+ path: string;
611
+ auth: "apiKey";
612
+ description: string;
613
+ };
614
+ 'clients.notifications.get': {
615
+ method: "GET";
616
+ path: string;
617
+ auth: "apiKey";
618
+ description: string;
619
+ };
620
+ 'clients.notifications.update': {
621
+ method: "PATCH";
622
+ path: string;
623
+ auth: "apiKey";
624
+ description: string;
625
+ body: string[];
626
+ };
627
+ 'projects.notifications.get': {
628
+ method: "GET";
629
+ path: string;
630
+ auth: "apiKey";
631
+ description: string;
632
+ };
633
+ 'projects.notifications.update': {
634
+ method: "PATCH";
635
+ path: string;
636
+ auth: "apiKey";
637
+ description: string;
638
+ body: string[];
639
+ };
640
+ 'notifications.preview': {
641
+ method: "GET";
642
+ path: string;
643
+ auth: "apiKey";
644
+ description: string;
645
+ queryParams: string[];
646
+ };
647
+ 'audit.list': {
648
+ method: "GET";
649
+ path: string;
650
+ auth: "apiKey";
651
+ description: string;
652
+ queryParams: string[];
653
+ };
654
+ 'audit.target': {
655
+ method: "GET";
656
+ path: string;
657
+ auth: "apiKey";
658
+ description: string;
659
+ queryParams: string[];
660
+ };
661
+ };
525
662
  notes: {
526
663
  'notes.list': {
527
664
  method: "GET";
@@ -3,6 +3,7 @@ import { docsCommands } from './docs.js';
3
3
  import { capacityCommands } from './capacity.js';
4
4
  import { metricCommands } from './metrics.js';
5
5
  import { onboardingCommands } from './onboarding.js';
6
+ import { operatorCommands } from './operator.js';
6
7
  import { noteCommands } from './notes.js';
7
8
  import { portalCommands } from './portal.js';
8
9
  import { projectCommands } from './projects.js';
@@ -20,6 +21,7 @@ export const COMMAND_GROUPS = {
20
21
  usage: usageCommands,
21
22
  updates: updateCommands,
22
23
  onboarding: onboardingCommands,
24
+ operator: operatorCommands,
23
25
  notes: noteCommands,
24
26
  recurring: recurringCommands,
25
27
  metrics: metricCommands,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAK9C,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,MAAM,EAAE,cAAc;IACtB,OAAO,EAAE,cAAc;IACvB,QAAQ,EAAE,eAAe;IACzB,KAAK,EAAE,YAAY;IACnB,QAAQ,EAAE,gBAAgB;IAC1B,KAAK,EAAE,aAAa;IACpB,OAAO,EAAE,cAAc;IACvB,UAAU,EAAE,kBAAkB;IAC9B,KAAK,EAAE,YAAY;IACnB,SAAS,EAAE,iBAAiB;IAC5B,OAAO,EAAE,cAAc;IACvB,IAAI,EAAE,YAAY;IAClB,MAAM,EAAE,cAAc;CACgB,CAAC;AAEzC,MAAM,CAAC,MAAM,QAAQ,GAA+B,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAK9C,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,MAAM,EAAE,cAAc;IACtB,OAAO,EAAE,cAAc;IACvB,QAAQ,EAAE,eAAe;IACzB,KAAK,EAAE,YAAY;IACnB,QAAQ,EAAE,gBAAgB;IAC1B,KAAK,EAAE,aAAa;IACpB,OAAO,EAAE,cAAc;IACvB,UAAU,EAAE,kBAAkB;IAC9B,QAAQ,EAAE,gBAAgB;IAC1B,KAAK,EAAE,YAAY;IACnB,SAAS,EAAE,iBAAiB;IAC5B,OAAO,EAAE,cAAc;IACvB,IAAI,EAAE,YAAY;IAClB,MAAM,EAAE,cAAc;CACgB,CAAC;AAEzC,MAAM,CAAC,MAAM,QAAQ,GAA+B,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC"}
@@ -0,0 +1,137 @@
1
+ export declare const operatorCommands: {
2
+ inbox: {
3
+ method: "GET";
4
+ path: string;
5
+ auth: "apiKey";
6
+ description: string;
7
+ queryParams: string[];
8
+ };
9
+ 'inbox.mark-read': {
10
+ method: "POST";
11
+ path: string;
12
+ auth: "apiKey";
13
+ description: string;
14
+ };
15
+ 'inbox.mark-client-read': {
16
+ method: "POST";
17
+ path: string;
18
+ auth: "apiKey";
19
+ description: string;
20
+ };
21
+ 'inbox.mark-project-read': {
22
+ method: "POST";
23
+ path: string;
24
+ auth: "apiKey";
25
+ description: string;
26
+ };
27
+ 'inbox.mark-all-read': {
28
+ method: "POST";
29
+ path: string;
30
+ auth: "apiKey";
31
+ description: string;
32
+ };
33
+ 'reports.monthly': {
34
+ method: "GET";
35
+ path: string;
36
+ auth: "apiKey";
37
+ description: string;
38
+ queryParams: string[];
39
+ };
40
+ 'client.timeline': {
41
+ method: "GET";
42
+ path: string;
43
+ auth: "apiKey";
44
+ description: string;
45
+ queryParams: string[];
46
+ };
47
+ 'project.timeline': {
48
+ method: "GET";
49
+ path: string;
50
+ auth: "apiKey";
51
+ description: string;
52
+ queryParams: string[];
53
+ };
54
+ 'ops-health': {
55
+ method: "GET";
56
+ path: string;
57
+ auth: "apiKey";
58
+ description: string;
59
+ };
60
+ 'smoke.portal': {
61
+ method: "GET";
62
+ path: string;
63
+ auth: "apiKey";
64
+ description: string;
65
+ };
66
+ 'smoke.docs': {
67
+ method: "GET";
68
+ path: string;
69
+ auth: "apiKey";
70
+ description: string;
71
+ };
72
+ 'smoke.capacity': {
73
+ method: "GET";
74
+ path: string;
75
+ auth: "apiKey";
76
+ description: string;
77
+ };
78
+ 'smoke.recurring': {
79
+ method: "GET";
80
+ path: string;
81
+ auth: "apiKey";
82
+ description: string;
83
+ };
84
+ 'smoke.notifications': {
85
+ method: "GET";
86
+ path: string;
87
+ auth: "apiKey";
88
+ description: string;
89
+ };
90
+ 'clients.notifications.get': {
91
+ method: "GET";
92
+ path: string;
93
+ auth: "apiKey";
94
+ description: string;
95
+ };
96
+ 'clients.notifications.update': {
97
+ method: "PATCH";
98
+ path: string;
99
+ auth: "apiKey";
100
+ description: string;
101
+ body: string[];
102
+ };
103
+ 'projects.notifications.get': {
104
+ method: "GET";
105
+ path: string;
106
+ auth: "apiKey";
107
+ description: string;
108
+ };
109
+ 'projects.notifications.update': {
110
+ method: "PATCH";
111
+ path: string;
112
+ auth: "apiKey";
113
+ description: string;
114
+ body: string[];
115
+ };
116
+ 'notifications.preview': {
117
+ method: "GET";
118
+ path: string;
119
+ auth: "apiKey";
120
+ description: string;
121
+ queryParams: string[];
122
+ };
123
+ 'audit.list': {
124
+ method: "GET";
125
+ path: string;
126
+ auth: "apiKey";
127
+ description: string;
128
+ queryParams: string[];
129
+ };
130
+ 'audit.target': {
131
+ method: "GET";
132
+ path: string;
133
+ auth: "apiKey";
134
+ description: string;
135
+ queryParams: string[];
136
+ };
137
+ };
@@ -0,0 +1,138 @@
1
+ export const operatorCommands = {
2
+ inbox: {
3
+ method: 'GET',
4
+ path: '/api/admin/operator-inbox',
5
+ auth: 'apiKey',
6
+ description: 'Review operator inbox',
7
+ queryParams: ['clientId|client', 'projectId|project', 'since', 'unreadOnly|unread', 'limit'],
8
+ },
9
+ 'inbox.mark-read': {
10
+ method: 'POST',
11
+ path: '/api/admin/operator-inbox/read/:itemId',
12
+ auth: 'apiKey',
13
+ description: 'Mark one inbox item read',
14
+ },
15
+ 'inbox.mark-client-read': {
16
+ method: 'POST',
17
+ path: '/api/admin/operator-inbox/read-client/:clientId',
18
+ auth: 'apiKey',
19
+ description: 'Mark a client inbox section read',
20
+ },
21
+ 'inbox.mark-project-read': {
22
+ method: 'POST',
23
+ path: '/api/admin/operator-inbox/read-project/:projectId',
24
+ auth: 'apiKey',
25
+ description: 'Mark a project inbox section read',
26
+ },
27
+ 'inbox.mark-all-read': {
28
+ method: 'POST',
29
+ path: '/api/admin/operator-inbox/read-all',
30
+ auth: 'apiKey',
31
+ description: 'Mark all current inbox items read',
32
+ },
33
+ 'reports.monthly': {
34
+ method: 'GET',
35
+ path: '/api/admin/clients/:clientId/reports/monthly',
36
+ auth: 'apiKey',
37
+ description: 'Generate monthly client report',
38
+ queryParams: ['period'],
39
+ },
40
+ 'client.timeline': {
41
+ method: 'GET',
42
+ path: '/api/admin/clients/:clientId/timeline',
43
+ auth: 'apiKey',
44
+ description: 'Show client timeline',
45
+ queryParams: ['projectId|project', 'type', 'since', 'until', 'limit'],
46
+ },
47
+ 'project.timeline': {
48
+ method: 'GET',
49
+ path: '/api/admin/projects/:projectId/timeline',
50
+ auth: 'apiKey',
51
+ description: 'Show project timeline',
52
+ queryParams: ['type', 'since', 'until', 'limit'],
53
+ },
54
+ 'ops-health': {
55
+ method: 'GET',
56
+ path: '/api/admin/ops-health',
57
+ auth: 'apiKey',
58
+ description: 'Show operational health summary',
59
+ },
60
+ 'smoke.portal': {
61
+ method: 'GET',
62
+ path: '/api/admin/clients/:id',
63
+ auth: 'apiKey',
64
+ description: 'Read-only portal smoke check',
65
+ },
66
+ 'smoke.docs': {
67
+ method: 'GET',
68
+ path: '/api/admin/clients/:id/docs/documents',
69
+ auth: 'apiKey',
70
+ description: 'Read-only Docs smoke check',
71
+ },
72
+ 'smoke.capacity': {
73
+ method: 'GET',
74
+ path: '/api/admin/projects/:projectId/capacity-summary',
75
+ auth: 'apiKey',
76
+ description: 'Read-only capacity smoke check',
77
+ },
78
+ 'smoke.recurring': {
79
+ method: 'GET',
80
+ path: '/api/admin/projects/:projectId/recurring-checkpoints',
81
+ auth: 'apiKey',
82
+ description: 'Read-only recurring smoke check',
83
+ },
84
+ 'smoke.notifications': {
85
+ method: 'GET',
86
+ path: '/api/admin/smoke/notifications/:clientId',
87
+ auth: 'apiKey',
88
+ description: 'Read-only notification smoke check',
89
+ },
90
+ 'clients.notifications.get': {
91
+ method: 'GET',
92
+ path: '/api/admin/clients/:id/notification-preferences',
93
+ auth: 'apiKey',
94
+ description: 'Show client notification preferences',
95
+ },
96
+ 'clients.notifications.update': {
97
+ method: 'PATCH',
98
+ path: '/api/admin/clients/:id/notification-preferences',
99
+ auth: 'apiKey',
100
+ description: 'Update client notification preferences',
101
+ body: ['mode', 'digestFrequency'],
102
+ },
103
+ 'projects.notifications.get': {
104
+ method: 'GET',
105
+ path: '/api/admin/projects/:id/notification-preferences',
106
+ auth: 'apiKey',
107
+ description: 'Show project notification preferences',
108
+ },
109
+ 'projects.notifications.update': {
110
+ method: 'PATCH',
111
+ path: '/api/admin/projects/:id/notification-preferences',
112
+ auth: 'apiKey',
113
+ description: 'Update project notification preferences',
114
+ body: ['mode', 'digestFrequency'],
115
+ },
116
+ 'notifications.preview': {
117
+ method: 'GET',
118
+ path: '/api/admin/notifications/preview/:eventType',
119
+ auth: 'apiKey',
120
+ description: 'Preview notification rendering without sending',
121
+ queryParams: ['clientId|client', 'projectId|project'],
122
+ },
123
+ 'audit.list': {
124
+ method: 'GET',
125
+ path: '/api/admin/audit-events',
126
+ auth: 'apiKey',
127
+ description: 'List operational audit events',
128
+ queryParams: ['clientId|client', 'projectId|project', 'actorId|actor', 'action', 'targetType', 'targetId', 'since', 'until', 'limit'],
129
+ },
130
+ 'audit.target': {
131
+ method: 'GET',
132
+ path: '/api/admin/audit-events',
133
+ auth: 'apiKey',
134
+ description: 'List audit events for one target',
135
+ queryParams: ['targetType', 'targetId', 'limit'],
136
+ },
137
+ };
138
+ //# sourceMappingURL=operator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operator.js","sourceRoot":"","sources":["../../commands/operator.ts"],"names":[],"mappings":"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"}
@@ -299,6 +299,42 @@ function interpolatePath(template, id) {
299
299
  return template.replace(':id', id);
300
300
  }
301
301
 
302
+ function isUuid(value) {
303
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
304
+ }
305
+
306
+ function looksLikeOpaqueId(value) {
307
+ return isUuid(value) || /^[a-z]+-\d+$/i.test(value);
308
+ }
309
+
310
+ function pathParamEntity(commandKey, paramName) {
311
+ if (paramName.toLowerCase().includes('client')) return 'client';
312
+ if (paramName.toLowerCase().includes('project')) return 'project';
313
+ if (paramName === 'id' && commandKey.startsWith('clients.')) return 'client';
314
+ if (paramName === 'id' && commandKey.startsWith('projects.')) return 'project';
315
+ return null;
316
+ }
317
+
318
+ async function resolveNameParam(commandKey, paramName, value, flags) {
319
+ if (!value || looksLikeOpaqueId(value)) return value;
320
+ const entity = pathParamEntity(commandKey, paramName);
321
+ if (!entity) return value;
322
+ const params = new URLSearchParams({ q: value, type: entity, limit: '10' });
323
+ if (entity === 'project' && flags.client) params.set('client', flags.client);
324
+ if (entity === 'project' && flags.clientId) params.set('clientId', flags.clientId);
325
+ const data = await api('GET', `/api/admin/search?${params.toString()}`);
326
+ const rows = entity === 'client' ? (data.clients || []) : (data.projects || []);
327
+ const exact = rows.filter((row) => (row.name || '').toLowerCase() === value.toLowerCase());
328
+ const candidates = exact.length > 0 ? exact : rows;
329
+ if (candidates.length === 1) return candidates[0].id;
330
+ if (candidates.length === 0) console.error(`No ${entity} found for "${value}".`);
331
+ else {
332
+ console.error(`Ambiguous ${entity} name "${value}". Use an ID or narrow the search.`);
333
+ for (const row of candidates.slice(0, 5)) console.error(` ${row.name} [${row.id}]`);
334
+ }
335
+ exitGracefully(2);
336
+ }
337
+
302
338
  const HELP_ENUMS = {
303
339
  priority: 'low|normal|high|urgent',
304
340
  submittedBy: 'client|admin|va|system',
@@ -320,10 +356,11 @@ const HELP_ENUMS = {
320
356
  cadence: 'weekly|biweekly|monthly|quarterly|custom_days',
321
357
  cadenceType: 'weekly|biweekly|monthly|quarterly|custom_days',
322
358
  outputType: 'task|project_update_draft|project_update|email_reminder',
323
- notificationMode: 'silent|admin_only|client_on_acceptance|client_each_occurrence|client_digest_only',
324
359
  owner: 'admin|client|shared',
325
360
  requiresClientAcceptance: 'true|false',
326
361
  requiresAdminAcceptance: 'true|false',
362
+ mode: 'muted|portal_only|admin_only|material_updates|digest|all',
363
+ digestFrequency: 'daily|weekly|monthly',
327
364
  };
328
365
 
329
366
  function helpFlag(commandKey, field) {
@@ -339,6 +376,10 @@ function helpFlag(commandKey, field) {
339
376
  else if (commandKey.startsWith('capacity.')) hint = 'active|paused|ended';
340
377
  else if (commandKey.startsWith('tasks.')) hint = 'open|in_progress|done|blocked';
341
378
  }
379
+ if (field === 'notificationMode') {
380
+ if (commandKey.startsWith('recurring.')) hint = 'silent|admin_only|client_on_acceptance|client_each_occurrence|client_digest_only';
381
+ else if (commandKey.startsWith('tasks.')) hint = 'silent|ack_only|material_updates|all';
382
+ }
342
383
  return hint ? `--${field} ${hint}` : `--${field}`;
343
384
  }
344
385
 
@@ -353,6 +394,11 @@ function helpQueryFlag(field) {
353
394
  // ── Output Formatting ───────────────────────────────────────────
354
395
 
355
396
  function formatOutput(data, commandKey) {
397
+ if (commandKey === 'ops-health' && OUTPUT_JSON) {
398
+ console.log(COMPACT_JSON ? JSON.stringify(data) : JSON.stringify(data, null, 2));
399
+ if (data.status === 'critical') exitGracefully(1);
400
+ return;
401
+ }
356
402
  if (OUTPUT_JSON) {
357
403
  console.log(COMPACT_JSON ? JSON.stringify(data) : JSON.stringify(data, null, 2));
358
404
  return;
@@ -419,6 +465,111 @@ function formatOutput(data, commandKey) {
419
465
  return;
420
466
  }
421
467
 
468
+ if (commandKey === 'inbox') {
469
+ const sections = data.sections || {};
470
+ console.log('\nOperator Inbox');
471
+ console.log('-'.repeat(80));
472
+ for (const [key, section] of Object.entries(sections)) {
473
+ const items = section.items || [];
474
+ if (items.length === 0) continue;
475
+ console.log(`\n${key} (${items.length})`);
476
+ for (const item of items) {
477
+ const unread = item.unread ? '*' : ' ';
478
+ const scope = [item.clientName, item.projectName].filter(Boolean).join(' / ');
479
+ console.log(` ${unread} ${item.summary} ${scope ? `- ${scope}` : ''} [${item.id}]`);
480
+ }
481
+ }
482
+ return;
483
+ }
484
+
485
+ if (commandKey === 'reports.monthly') {
486
+ const report = data.report;
487
+ if (!report) { console.log(JSON.stringify(data, null, 2)); return; }
488
+ if (COMPACT_JSON) {
489
+ console.log(`${report.client.name}: ${report.period} - ${report.completedWork.length} done, ${report.openWork.length} open`);
490
+ return;
491
+ }
492
+ console.log(`\nMonthly Report: ${report.client.name} (${report.period})`);
493
+ console.log('-'.repeat(80));
494
+ console.log(`Completed work: ${report.completedWork.length}`);
495
+ for (const item of report.completedWork) console.log(` - ${item.title}`);
496
+ console.log(`Open work: ${report.openWork.length}`);
497
+ for (const item of report.openWork) console.log(` - ${item.title} [${item.status}]`);
498
+ console.log(`Updates: ${report.updates.length}`);
499
+ console.log(`Invoices: ${report.invoices.length}`);
500
+ console.log(`Capacity items: ${report.capacity.length}`);
501
+ return;
502
+ }
503
+
504
+ if (commandKey === 'client.timeline' || commandKey === 'project.timeline') {
505
+ const items = data.data || [];
506
+ if (items.length === 0) { console.log('No timeline events found.'); return; }
507
+ console.log(`\nTimeline (${items.length})`);
508
+ console.log('-'.repeat(80));
509
+ for (const item of items) {
510
+ const scope = [item.clientName, item.projectName].filter(Boolean).join(' / ');
511
+ console.log(` ${item.type}: ${item.summary}${scope ? ` - ${scope}` : ''} [${item.sourceId}]`);
512
+ }
513
+ return;
514
+ }
515
+
516
+ if (commandKey === 'ops-health') {
517
+ console.log(`Operational health: ${data.status}`);
518
+ for (const [key, value] of Object.entries(data.failures || {})) {
519
+ console.log(` ${key}: ${value}`);
520
+ }
521
+ if (data.status === 'critical') exitGracefully(1);
522
+ return;
523
+ }
524
+
525
+ if (commandKey === 'smoke.notifications') {
526
+ const smoke = data.smoke || {};
527
+ console.log(`Notification smoke: ${smoke.client?.name || 'client'}`);
528
+ console.log(` Read-only dry run: ${smoke.dryRun === false ? 'false' : 'true'}`);
529
+ console.log(` notificationsEnabled: ${smoke.client?.notificationsEnabled}`);
530
+ console.log(` preference: ${smoke.preference?.mode || 'n/a'}`);
531
+ console.log(` failed deliveries: ${smoke.failedCount ?? 0}`);
532
+ console.log(' Would send: none');
533
+ console.log(' Would create: none');
534
+ return;
535
+ }
536
+
537
+ if (
538
+ commandKey === 'clients.notifications.get' ||
539
+ commandKey === 'clients.notifications.update' ||
540
+ commandKey === 'projects.notifications.get' ||
541
+ commandKey === 'projects.notifications.update'
542
+ ) {
543
+ const preference = data.preference || {};
544
+ console.log(`Notification preference: ${preference.mode || 'n/a'}`);
545
+ if (preference.digestFrequency) console.log(` Digest: ${preference.digestFrequency}`);
546
+ if (preference.inheritedFromClient) console.log(' Inherited from client preference.');
547
+ if (preference.inheritedFromNotificationsEnabled) console.log(' Inherited from notificationsEnabled.');
548
+ return;
549
+ }
550
+
551
+ if (commandKey === 'notifications.preview') {
552
+ const preview = data.preview || {};
553
+ console.log(`Notification preview: ${preview.subject || preview.eventType}`);
554
+ console.log(` Audience: ${(preview.audience || []).join(', ') || 'none'}`);
555
+ console.log(` Mode: ${preview.mode || 'n/a'}`);
556
+ console.log(` Thread: ${preview.threadKey || 'n/a'}`);
557
+ console.log('');
558
+ console.log(preview.body || '');
559
+ return;
560
+ }
561
+
562
+ if (commandKey === 'audit.list' || commandKey === 'audit.target') {
563
+ const items = data.data || [];
564
+ if (items.length === 0) { console.log('No audit events found.'); return; }
565
+ console.log(`\nAudit Events (${items.length})`);
566
+ console.log('-'.repeat(80));
567
+ for (const item of items) {
568
+ console.log(` ${item.action}: ${item.targetType}/${item.targetId} [${item.id}]`);
569
+ }
570
+ return;
571
+ }
572
+
422
573
  if (commandKey === 'projects.get') {
423
574
  const p = data.project;
424
575
  console.log(`\n${p.name} [${p.status}]`);
@@ -775,6 +926,11 @@ if (!resource || resource === 'help' || resource === '--help') {
775
926
  }
776
927
  console.log(`\nConfig: PORTAL_API_URL, PORTAL_API_KEY, PORTAL_TOKEN (or ~/.klevar/portal.env)`);
777
928
  console.log(`Target: ${BASE_URL}`);
929
+ console.log('\nExamples:');
930
+ console.log(' klevar-portal inbox --unread --compact');
931
+ console.log(' klevar-portal client timeline "Acme Ltd" --type task');
932
+ console.log(' klevar-portal notifications preview project.status_changed --client "Acme Ltd" --project "Retainer"');
933
+ console.log(' klevar-portal audit target task <taskId>');
778
934
  exitGracefully(0);
779
935
  }
780
936
 
@@ -824,19 +980,25 @@ if (supportsCommentContentInput(commandKey)) {
824
980
  }
825
981
  }
826
982
 
983
+ if (commandKey === 'audit.target' && positional.length >= 2) {
984
+ flags.targetType = positional[0];
985
+ flags.targetId = positional[1];
986
+ }
987
+
827
988
  // Interpolate path
828
989
  let path = cmd.path;
829
990
  const pathParams = [...path.matchAll(/:([A-Za-z][A-Za-z0-9_]*)/g)].map((match) => match[1]);
830
991
  if (pathParams.length > 0) {
831
- pathParams.forEach((paramName, index) => {
832
- const value = positional[index];
992
+ for (const [index, paramName] of pathParams.entries()) {
993
+ let value = positional[index];
833
994
  if (!value) {
834
995
  const ordinal = index === 0 ? 'an ID argument' : `argument ${index + 1} for :${paramName}`;
835
996
  console.error(`Command '${commandKey}' requires ${ordinal}.`);
836
997
  exitGracefully(1);
837
998
  }
999
+ value = await resolveNameParam(commandKey, paramName, value, flags);
838
1000
  path = path.replace(`:${paramName}`, value);
839
- });
1001
+ }
840
1002
  }
841
1003
 
842
1004
  // Append query parameters for GET commands with filters
@@ -855,6 +1017,11 @@ if (cmd.queryParams || cmd.fixedQuery) {
855
1017
  if (qs) path += (path.includes('?') ? '&' : '?') + qs;
856
1018
  }
857
1019
 
1020
+ if (commandKey.startsWith('smoke.') && (flags.write === 'true' || flags.send === 'true')) {
1021
+ console.error(`Command '${commandKey}' is read-only; --write/--send are not supported for this smoke check.`);
1022
+ exitGracefully(2);
1023
+ }
1024
+
858
1025
  // Build body from flags or fixedBody
859
1026
  let body = undefined;
860
1027
  if (cmd.fixedBody) {
@@ -884,6 +1051,13 @@ if (supportsCommentContentInput(commandKey) && !body && positional[pathParams.le
884
1051
  body = { content: normalizeCliMultiline(positional.slice(pathParams.length).join(' ')) };
885
1052
  }
886
1053
 
1054
+ if (flags['dry-run'] === 'true' && ['POST', 'PATCH', 'DELETE'].includes(cmd.method)) {
1055
+ console.log(`Dry run: ${cmd.method} ${path}`);
1056
+ if (body) console.log(COMPACT_JSON ? JSON.stringify(body) : JSON.stringify(body, null, 2));
1057
+ else console.log('No request body.');
1058
+ exitGracefully(0);
1059
+ }
1060
+
887
1061
  // ── Search Command ──
888
1062
  if (commandKey === 'search') {
889
1063
  const q = [id, ...positional.slice(1)].filter(Boolean).join(' ');
@@ -891,8 +1065,13 @@ if (commandKey === 'search') {
891
1065
  console.error('Usage: search <term>');
892
1066
  exitGracefully(1);
893
1067
  }
894
- const data = await api('GET', `/api/admin/search?q=${encodeURIComponent(q)}`);
895
- const hasResults = data.projects.length + data.tasks.length + data.updates.length > 0;
1068
+ const params = new URLSearchParams({ q });
1069
+ for (const key of ['client', 'clientId', 'project', 'projectId', 'type', 'limit']) {
1070
+ if (flags[key] !== undefined) params.set(key, flags[key]);
1071
+ }
1072
+ const data = await api('GET', `/api/admin/search?${params.toString()}`);
1073
+ const resultGroups = ['clients', 'projects', 'tasks', 'updates', 'comments', 'notes', 'docs', 'capacity'];
1074
+ const hasResults = resultGroups.some((group) => (data[group] || []).length > 0);
896
1075
 
897
1076
  if (!hasResults) {
898
1077
  console.log(`No results for "${q}"`);
@@ -902,7 +1081,15 @@ if (commandKey === 'search') {
902
1081
  console.log(`\nSearch: "${q}"`);
903
1082
  console.log('─'.repeat(50));
904
1083
 
905
- if (data.projects.length > 0) {
1084
+ if (data.clients?.length > 0) {
1085
+ console.log('\nClients:');
1086
+ data.clients.forEach((c) => {
1087
+ const company = c.company ? ` (${c.company})` : '';
1088
+ console.log(` • ${c.name}${company} [${c.status}] [${c.id}]`);
1089
+ });
1090
+ }
1091
+
1092
+ if ((data.projects || []).length > 0) {
906
1093
  console.log('\nProjects:');
907
1094
  data.projects.forEach((p) => {
908
1095
  const visibility = p.visibility ? ` [${p.visibility}]` : '';
@@ -912,7 +1099,7 @@ if (commandKey === 'search') {
912
1099
  console.log('\nProjects: (none)');
913
1100
  }
914
1101
 
915
- if (data.tasks.length > 0) {
1102
+ if ((data.tasks || []).length > 0) {
916
1103
  console.log('\nTasks:');
917
1104
  data.tasks.forEach((t) => {
918
1105
  const prio = t.priority && t.priority !== 'normal' ? ` (${t.priority})` : '';
@@ -922,7 +1109,7 @@ if (commandKey === 'search') {
922
1109
  console.log('\nTasks: (none)');
923
1110
  }
924
1111
 
925
- if (data.updates.length > 0) {
1112
+ if ((data.updates || []).length > 0) {
926
1113
  console.log('\nUpdates:');
927
1114
  data.updates.forEach((u) => {
928
1115
  const vis = u.visibility === 'internal' ? ' [INTERNAL]' : '';
@@ -932,6 +1119,16 @@ if (commandKey === 'search') {
932
1119
  console.log('\nUpdates: (none)');
933
1120
  }
934
1121
 
1122
+ for (const [label, key] of [['Comments', 'comments'], ['Notes', 'notes'], ['Docs', 'docs'], ['Capacity', 'capacity']]) {
1123
+ const items = data[key] || [];
1124
+ if (items.length === 0) continue;
1125
+ console.log(`\n${label}:`);
1126
+ items.forEach((item) => {
1127
+ const text = item.title || item.contentPreview || item.documentNumber || item.documentType || item.status || item.billableStatus || item.id;
1128
+ console.log(` • ${text} [${item.id}]`);
1129
+ });
1130
+ }
1131
+
935
1132
  exitGracefully(0);
936
1133
  }
937
1134
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@klevar/portal-cli",
3
- "version": "0.1.19",
3
+ "version": "0.1.21",
4
4
  "description": "First-class npm CLI for the Klevar Client Management Portal",
5
5
  "type": "module",
6
6
  "bin": {