@klevar/portal-cli 0.1.20 → 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.
- package/dist/commands/_exemptions.d.ts +6 -0
- package/dist/commands/_exemptions.js +7 -0
- package/dist/commands/_exemptions.js.map +1 -1
- package/dist/commands/index.d.ts +137 -0
- package/dist/commands/index.js +2 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/operator.d.ts +137 -0
- package/dist/commands/operator.js +138 -0
- package/dist/commands/operator.js.map +1 -0
- package/dist/lib/legacy-runner.js +202 -8
- package/package.json +1 -1
|
@@ -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"}
|
package/dist/commands/index.d.ts
CHANGED
|
@@ -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";
|
package/dist/commands/index.js
CHANGED
|
@@ -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',
|
|
@@ -323,6 +359,8 @@ const HELP_ENUMS = {
|
|
|
323
359
|
owner: 'admin|client|shared',
|
|
324
360
|
requiresClientAcceptance: 'true|false',
|
|
325
361
|
requiresAdminAcceptance: 'true|false',
|
|
362
|
+
mode: 'muted|portal_only|admin_only|material_updates|digest|all',
|
|
363
|
+
digestFrequency: 'daily|weekly|monthly',
|
|
326
364
|
};
|
|
327
365
|
|
|
328
366
|
function helpFlag(commandKey, field) {
|
|
@@ -356,6 +394,11 @@ function helpQueryFlag(field) {
|
|
|
356
394
|
// ── Output Formatting ───────────────────────────────────────────
|
|
357
395
|
|
|
358
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
|
+
}
|
|
359
402
|
if (OUTPUT_JSON) {
|
|
360
403
|
console.log(COMPACT_JSON ? JSON.stringify(data) : JSON.stringify(data, null, 2));
|
|
361
404
|
return;
|
|
@@ -422,6 +465,111 @@ function formatOutput(data, commandKey) {
|
|
|
422
465
|
return;
|
|
423
466
|
}
|
|
424
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
|
+
|
|
425
573
|
if (commandKey === 'projects.get') {
|
|
426
574
|
const p = data.project;
|
|
427
575
|
console.log(`\n${p.name} [${p.status}]`);
|
|
@@ -778,6 +926,11 @@ if (!resource || resource === 'help' || resource === '--help') {
|
|
|
778
926
|
}
|
|
779
927
|
console.log(`\nConfig: PORTAL_API_URL, PORTAL_API_KEY, PORTAL_TOKEN (or ~/.klevar/portal.env)`);
|
|
780
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>');
|
|
781
934
|
exitGracefully(0);
|
|
782
935
|
}
|
|
783
936
|
|
|
@@ -827,19 +980,25 @@ if (supportsCommentContentInput(commandKey)) {
|
|
|
827
980
|
}
|
|
828
981
|
}
|
|
829
982
|
|
|
983
|
+
if (commandKey === 'audit.target' && positional.length >= 2) {
|
|
984
|
+
flags.targetType = positional[0];
|
|
985
|
+
flags.targetId = positional[1];
|
|
986
|
+
}
|
|
987
|
+
|
|
830
988
|
// Interpolate path
|
|
831
989
|
let path = cmd.path;
|
|
832
990
|
const pathParams = [...path.matchAll(/:([A-Za-z][A-Za-z0-9_]*)/g)].map((match) => match[1]);
|
|
833
991
|
if (pathParams.length > 0) {
|
|
834
|
-
pathParams.
|
|
835
|
-
|
|
992
|
+
for (const [index, paramName] of pathParams.entries()) {
|
|
993
|
+
let value = positional[index];
|
|
836
994
|
if (!value) {
|
|
837
995
|
const ordinal = index === 0 ? 'an ID argument' : `argument ${index + 1} for :${paramName}`;
|
|
838
996
|
console.error(`Command '${commandKey}' requires ${ordinal}.`);
|
|
839
997
|
exitGracefully(1);
|
|
840
998
|
}
|
|
999
|
+
value = await resolveNameParam(commandKey, paramName, value, flags);
|
|
841
1000
|
path = path.replace(`:${paramName}`, value);
|
|
842
|
-
}
|
|
1001
|
+
}
|
|
843
1002
|
}
|
|
844
1003
|
|
|
845
1004
|
// Append query parameters for GET commands with filters
|
|
@@ -858,6 +1017,11 @@ if (cmd.queryParams || cmd.fixedQuery) {
|
|
|
858
1017
|
if (qs) path += (path.includes('?') ? '&' : '?') + qs;
|
|
859
1018
|
}
|
|
860
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
|
+
|
|
861
1025
|
// Build body from flags or fixedBody
|
|
862
1026
|
let body = undefined;
|
|
863
1027
|
if (cmd.fixedBody) {
|
|
@@ -887,6 +1051,13 @@ if (supportsCommentContentInput(commandKey) && !body && positional[pathParams.le
|
|
|
887
1051
|
body = { content: normalizeCliMultiline(positional.slice(pathParams.length).join(' ')) };
|
|
888
1052
|
}
|
|
889
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
|
+
|
|
890
1061
|
// ── Search Command ──
|
|
891
1062
|
if (commandKey === 'search') {
|
|
892
1063
|
const q = [id, ...positional.slice(1)].filter(Boolean).join(' ');
|
|
@@ -894,8 +1065,13 @@ if (commandKey === 'search') {
|
|
|
894
1065
|
console.error('Usage: search <term>');
|
|
895
1066
|
exitGracefully(1);
|
|
896
1067
|
}
|
|
897
|
-
const
|
|
898
|
-
const
|
|
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);
|
|
899
1075
|
|
|
900
1076
|
if (!hasResults) {
|
|
901
1077
|
console.log(`No results for "${q}"`);
|
|
@@ -905,7 +1081,15 @@ if (commandKey === 'search') {
|
|
|
905
1081
|
console.log(`\nSearch: "${q}"`);
|
|
906
1082
|
console.log('─'.repeat(50));
|
|
907
1083
|
|
|
908
|
-
if (data.
|
|
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) {
|
|
909
1093
|
console.log('\nProjects:');
|
|
910
1094
|
data.projects.forEach((p) => {
|
|
911
1095
|
const visibility = p.visibility ? ` [${p.visibility}]` : '';
|
|
@@ -915,7 +1099,7 @@ if (commandKey === 'search') {
|
|
|
915
1099
|
console.log('\nProjects: (none)');
|
|
916
1100
|
}
|
|
917
1101
|
|
|
918
|
-
if (data.tasks.length > 0) {
|
|
1102
|
+
if ((data.tasks || []).length > 0) {
|
|
919
1103
|
console.log('\nTasks:');
|
|
920
1104
|
data.tasks.forEach((t) => {
|
|
921
1105
|
const prio = t.priority && t.priority !== 'normal' ? ` (${t.priority})` : '';
|
|
@@ -925,7 +1109,7 @@ if (commandKey === 'search') {
|
|
|
925
1109
|
console.log('\nTasks: (none)');
|
|
926
1110
|
}
|
|
927
1111
|
|
|
928
|
-
if (data.updates.length > 0) {
|
|
1112
|
+
if ((data.updates || []).length > 0) {
|
|
929
1113
|
console.log('\nUpdates:');
|
|
930
1114
|
data.updates.forEach((u) => {
|
|
931
1115
|
const vis = u.visibility === 'internal' ? ' [INTERNAL]' : '';
|
|
@@ -935,6 +1119,16 @@ if (commandKey === 'search') {
|
|
|
935
1119
|
console.log('\nUpdates: (none)');
|
|
936
1120
|
}
|
|
937
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
|
+
|
|
938
1132
|
exitGracefully(0);
|
|
939
1133
|
}
|
|
940
1134
|
|