@klevar/portal-cli 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
try {
|
|
3
|
+
// @ts-expect-error legacy JavaScript execution engine is copied during post-build.
|
|
4
|
+
await import('../lib/legacy-runner.js');
|
|
5
|
+
}
|
|
6
|
+
catch (err) {
|
|
7
|
+
if (err &&
|
|
8
|
+
typeof err === 'object' &&
|
|
9
|
+
'message' in err &&
|
|
10
|
+
typeof err.message === 'string' &&
|
|
11
|
+
err.message.startsWith('CLI_EXIT_')) {
|
|
12
|
+
process.exitCode =
|
|
13
|
+
'code' in err && typeof err.code === 'number'
|
|
14
|
+
? err.code
|
|
15
|
+
: Number(err.message.replace('CLI_EXIT_', '')) || 1;
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
throw err;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
4
21
|
export {};
|
|
5
22
|
//# sourceMappingURL=klevar-portal.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"klevar-portal.js","sourceRoot":"","sources":["../../bin/klevar-portal.ts"],"names":[],"mappings":";AAEA,mFAAmF;
|
|
1
|
+
{"version":3,"file":"klevar-portal.js","sourceRoot":"","sources":["../../bin/klevar-portal.ts"],"names":[],"mappings":";AAEA,IAAI,CAAC;IACH,mFAAmF;IACnF,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAAC;AAC1C,CAAC;AAAC,OAAO,GAAG,EAAE,CAAC;IACb,IACE,GAAG;QACH,OAAO,GAAG,KAAK,QAAQ;QACvB,SAAS,IAAI,GAAG;QAChB,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ;QAC/B,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,EACnC,CAAC;QACD,OAAO,CAAC,QAAQ;YACd,MAAM,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ;gBAC3C,CAAC,CAAC,GAAG,CAAC,IAAI;gBACV,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IAC1D,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
|
|
@@ -25,6 +25,18 @@ import { join } from 'node:path';
|
|
|
25
25
|
import { homedir } from 'node:os';
|
|
26
26
|
import { COMMANDS } from '../commands/index.js';
|
|
27
27
|
|
|
28
|
+
class CliExit extends Error {
|
|
29
|
+
constructor(code = 1) {
|
|
30
|
+
super(`CLI_EXIT_${code}`);
|
|
31
|
+
this.code = code;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function exitGracefully(code = 1) {
|
|
36
|
+
process.exitCode = code;
|
|
37
|
+
throw new CliExit(code);
|
|
38
|
+
}
|
|
39
|
+
|
|
28
40
|
// ── Credential Loading ──────────────────────────────────────────
|
|
29
41
|
|
|
30
42
|
function loadEnvFile(filePath) {
|
|
@@ -58,7 +70,7 @@ function requireApiKey() {
|
|
|
58
70
|
if (!API_KEY) {
|
|
59
71
|
console.error('Error: PORTAL_API_KEY is required');
|
|
60
72
|
console.error('Set it via env var or create ~/.klevar/portal.env');
|
|
61
|
-
|
|
73
|
+
exitGracefully(2);
|
|
62
74
|
}
|
|
63
75
|
}
|
|
64
76
|
|
|
@@ -66,7 +78,7 @@ function requirePortalToken() {
|
|
|
66
78
|
if (!PORTAL_TOKEN) {
|
|
67
79
|
console.error('Error: PORTAL_TOKEN is required for portal commands');
|
|
68
80
|
console.error('Set it via env var, --portal-token, or ~/.klevar/portal.env');
|
|
69
|
-
|
|
81
|
+
exitGracefully(2);
|
|
70
82
|
}
|
|
71
83
|
}
|
|
72
84
|
|
|
@@ -113,7 +125,7 @@ async function api(method, path, body, auth = 'apiKey') {
|
|
|
113
125
|
if (!res.ok) {
|
|
114
126
|
const err = await res.json().catch(() => ({ error: { message: res.statusText } }));
|
|
115
127
|
printApiError(res.status, err);
|
|
116
|
-
|
|
128
|
+
exitGracefully(1);
|
|
117
129
|
}
|
|
118
130
|
|
|
119
131
|
if (res.status === 204) return null;
|
|
@@ -137,7 +149,7 @@ async function apiDownload(path, outputPath, auth = 'apiKey') {
|
|
|
137
149
|
if (!res.ok) {
|
|
138
150
|
const err = await res.json().catch(() => ({ error: { message: res.statusText } }));
|
|
139
151
|
printApiError(res.status, err);
|
|
140
|
-
|
|
152
|
+
exitGracefully(1);
|
|
141
153
|
}
|
|
142
154
|
|
|
143
155
|
const contentType = res.headers.get('content-type') || '';
|
|
@@ -158,7 +170,7 @@ async function apiDownload(path, outputPath, auth = 'apiKey') {
|
|
|
158
170
|
|
|
159
171
|
if (!outputPath) {
|
|
160
172
|
console.error('Error: --output is required when the API returns PDF bytes');
|
|
161
|
-
|
|
173
|
+
exitGracefully(1);
|
|
162
174
|
}
|
|
163
175
|
|
|
164
176
|
const bytes = Buffer.from(await res.arrayBuffer());
|
|
@@ -170,7 +182,7 @@ async function downloadPublicUrl(url, outputPath) {
|
|
|
170
182
|
const res = await fetch(url);
|
|
171
183
|
if (!res.ok) {
|
|
172
184
|
console.error(`Error ${res.status}: failed to download signed URL`);
|
|
173
|
-
|
|
185
|
+
exitGracefully(1);
|
|
174
186
|
}
|
|
175
187
|
const bytes = Buffer.from(await res.arrayBuffer());
|
|
176
188
|
writeFileSync(outputPath, bytes);
|
|
@@ -209,7 +221,7 @@ async function apiMultipart(method, path, fields, filePaths) {
|
|
|
209
221
|
if (!res.ok) {
|
|
210
222
|
const err = await res.json().catch(() => ({ error: { message: res.statusText } }));
|
|
211
223
|
printApiError(res.status, err);
|
|
212
|
-
|
|
224
|
+
exitGracefully(1);
|
|
213
225
|
}
|
|
214
226
|
if (res.status === 204) return null;
|
|
215
227
|
return res.json();
|
|
@@ -613,7 +625,7 @@ if (!resource || resource === 'help' || resource === '--help') {
|
|
|
613
625
|
}
|
|
614
626
|
console.log(`\nConfig: PORTAL_API_URL, PORTAL_API_KEY, PORTAL_TOKEN (or ~/.klevar/portal.env)`);
|
|
615
627
|
console.log(`Target: ${BASE_URL}`);
|
|
616
|
-
|
|
628
|
+
exitGracefully(0);
|
|
617
629
|
}
|
|
618
630
|
|
|
619
631
|
// Resolve command key — handle single-word commands (e.g. "search <term>")
|
|
@@ -637,7 +649,7 @@ if (!cmd && COMMANDS[resource]) {
|
|
|
637
649
|
if (!cmd) {
|
|
638
650
|
console.error(`Unknown command: ${commandKey}`);
|
|
639
651
|
console.error(`Run 'klevar-portal help' for available commands.`);
|
|
640
|
-
|
|
652
|
+
exitGracefully(1);
|
|
641
653
|
}
|
|
642
654
|
|
|
643
655
|
// Parse remaining args
|
|
@@ -659,7 +671,7 @@ if (pathParams.length > 0) {
|
|
|
659
671
|
if (!value) {
|
|
660
672
|
const ordinal = index === 0 ? 'an ID argument' : `argument ${index + 1} for :${paramName}`;
|
|
661
673
|
console.error(`Command '${commandKey}' requires ${ordinal}.`);
|
|
662
|
-
|
|
674
|
+
exitGracefully(1);
|
|
663
675
|
}
|
|
664
676
|
path = path.replace(`:${paramName}`, value);
|
|
665
677
|
});
|
|
@@ -708,14 +720,14 @@ if (commandKey === 'search') {
|
|
|
708
720
|
const q = [id, ...positional.slice(1)].filter(Boolean).join(' ');
|
|
709
721
|
if (!q) {
|
|
710
722
|
console.error('Usage: search <term>');
|
|
711
|
-
|
|
723
|
+
exitGracefully(1);
|
|
712
724
|
}
|
|
713
725
|
const data = await api('GET', `/api/admin/search?q=${encodeURIComponent(q)}`);
|
|
714
726
|
const hasResults = data.projects.length + data.tasks.length + data.updates.length > 0;
|
|
715
727
|
|
|
716
728
|
if (!hasResults) {
|
|
717
729
|
console.log(`No results for "${q}"`);
|
|
718
|
-
|
|
730
|
+
exitGracefully(0);
|
|
719
731
|
}
|
|
720
732
|
|
|
721
733
|
console.log(`\nSearch: "${q}"`);
|
|
@@ -750,7 +762,7 @@ if (commandKey === 'search') {
|
|
|
750
762
|
console.log('\nUpdates: (none)');
|
|
751
763
|
}
|
|
752
764
|
|
|
753
|
-
|
|
765
|
+
exitGracefully(0);
|
|
754
766
|
}
|
|
755
767
|
|
|
756
768
|
// ── Milestone Commands (custom logic: fetch → modify → PATCH) ──
|
|
@@ -759,7 +771,7 @@ if (cmd.method === 'CUSTOM' && resource === 'milestones') {
|
|
|
759
771
|
const projectId = id;
|
|
760
772
|
if (!projectId) {
|
|
761
773
|
console.error('Usage: milestones <action> <projectId> [--name "..."] or [index]');
|
|
762
|
-
|
|
774
|
+
exitGracefully(1);
|
|
763
775
|
}
|
|
764
776
|
|
|
765
777
|
// Fetch current project
|
|
@@ -777,23 +789,23 @@ if (cmd.method === 'CUSTOM' && resource === 'milestones') {
|
|
|
777
789
|
console.log(` ${i + 1}. ${icon} ${m.name} [${m.status}]`);
|
|
778
790
|
});
|
|
779
791
|
}
|
|
780
|
-
|
|
792
|
+
exitGracefully(0);
|
|
781
793
|
}
|
|
782
794
|
|
|
783
795
|
if (action === 'add') {
|
|
784
796
|
const name = flags.name || positional[1];
|
|
785
|
-
if (!name) { console.error('Usage: milestones add <projectId> --name "Milestone name"');
|
|
797
|
+
if (!name) { console.error('Usage: milestones add <projectId> --name "Milestone name"'); exitGracefully(1); }
|
|
786
798
|
milestones.push({ name, status: 'pending' });
|
|
787
799
|
await api('PATCH', `/api/admin/projects/${projectId}`, { milestonesJson: milestones });
|
|
788
800
|
console.log(`Added milestone: ${name} (${milestones.length} total)`);
|
|
789
|
-
|
|
801
|
+
exitGracefully(0);
|
|
790
802
|
}
|
|
791
803
|
|
|
792
804
|
if (action === 'done' || action === 'undo' || action === 'remove') {
|
|
793
805
|
const idx = parseInt(positional[1] || flags.index, 10) - 1;
|
|
794
806
|
if (isNaN(idx) || idx < 0 || idx >= milestones.length) {
|
|
795
807
|
console.error(`Invalid index. Use 1-${milestones.length}.`);
|
|
796
|
-
|
|
808
|
+
exitGracefully(1);
|
|
797
809
|
}
|
|
798
810
|
if (action === 'done') {
|
|
799
811
|
milestones[idx].status = 'done';
|
|
@@ -808,11 +820,11 @@ if (cmd.method === 'CUSTOM' && resource === 'milestones') {
|
|
|
808
820
|
await api('PATCH', `/api/admin/projects/${projectId}`, { milestonesJson: milestones });
|
|
809
821
|
console.log(`Removed: ${removed[0].name} (${milestones.length} remaining)`);
|
|
810
822
|
}
|
|
811
|
-
|
|
823
|
+
exitGracefully(0);
|
|
812
824
|
}
|
|
813
825
|
|
|
814
826
|
console.error(`Unknown milestone action: ${action}`);
|
|
815
|
-
|
|
827
|
+
exitGracefully(1);
|
|
816
828
|
}
|
|
817
829
|
|
|
818
830
|
// ── File Upload (multipart) ──
|
|
@@ -826,12 +838,12 @@ if (cmd.supportsFiles && flags.file) {
|
|
|
826
838
|
if (!fields.visibility) fields.visibility = 'client';
|
|
827
839
|
const data = await apiMultipart(cmd.method, path, fields, filePaths);
|
|
828
840
|
formatOutput(data, commandKey);
|
|
829
|
-
|
|
841
|
+
exitGracefully(0);
|
|
830
842
|
}
|
|
831
843
|
|
|
832
844
|
if (cmd.method === 'DOWNLOAD') {
|
|
833
845
|
await apiDownload(path, flags.output, cmd.auth);
|
|
834
|
-
|
|
846
|
+
exitGracefully(0);
|
|
835
847
|
}
|
|
836
848
|
|
|
837
849
|
// Execute
|