@klevar/portal-cli 0.1.2 → 0.1.3
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/README.md +48 -0
- package/dist/commands/capacity.js +2 -2
- package/dist/commands/capacity.js.map +1 -1
- package/dist/lib/legacy-runner.js +17 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,6 +43,54 @@ npx @klevar/portal-cli metrics push --external_ref "idealo:ksh.de" --source_ref
|
|
|
43
43
|
npx @klevar/portal-cli portal me --portal-token "<client-token>"
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
+
## Capacity And Usage
|
|
47
|
+
|
|
48
|
+
Capacity commands manage included allowances for a project or client. They are not timesheets.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npx @klevar/portal-cli capacity list <projectId>
|
|
52
|
+
npx @klevar/portal-cli capacity create <projectId> --name "Monthly Support" --laneKey support --unitType hours --periodType monthly --startDate 2026-06-01 --capacityAmount 12 --resetBehavior no_rollover --visibility client_visible_summary
|
|
53
|
+
npx @klevar/portal-cli capacity update <budgetId> --capacityAmount 20
|
|
54
|
+
npx @klevar/portal-cli capacity summary <projectId> --period 2026-06
|
|
55
|
+
npx @klevar/portal-cli capacity budget-summary <budgetId> --period 2026-06
|
|
56
|
+
npx @klevar/portal-cli capacity report <projectId> --period 2026-06
|
|
57
|
+
npx @klevar/portal-cli capacity pause <budgetId>
|
|
58
|
+
npx @klevar/portal-cli capacity resume <budgetId>
|
|
59
|
+
npx @klevar/portal-cli capacity end <budgetId>
|
|
60
|
+
npx @klevar/portal-cli capacity delete <budgetId>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Usage commands record consumed capacity.
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npx @klevar/portal-cli usage record <taskId> --budgetId <budgetId> --units 1.5 --usageDate 2026-06-03 --title "Maintenance support"
|
|
67
|
+
npx @klevar/portal-cli usage manual <projectId> --budgetId <budgetId> --units 1 --usageDate 2026-06-03 --title "Advisory call"
|
|
68
|
+
npx @klevar/portal-cli usage update <usageId> --units 2 --notes "Adjusted after review"
|
|
69
|
+
npx @klevar/portal-cli usage approve <usageId>
|
|
70
|
+
npx @klevar/portal-cli usage reject <usageId>
|
|
71
|
+
npx @klevar/portal-cli usage delete <usageId>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Current smoke-tested `unitType` values are `hours` and `credits`.
|
|
75
|
+
|
|
76
|
+
Supported `periodType` values:
|
|
77
|
+
|
|
78
|
+
- `monthly`: period keys use `YYYY-MM`.
|
|
79
|
+
- `weekly`: ISO week period keys use `YYYY-Www`, for example `2026-W23`.
|
|
80
|
+
|
|
81
|
+
Supported `visibility` values:
|
|
82
|
+
|
|
83
|
+
- `internal_only`: hidden from client portal capacity APIs.
|
|
84
|
+
- `client_visible_summary`: client can see summary totals only.
|
|
85
|
+
- `client_visible_detail`: client can see summary totals and visible usage entries.
|
|
86
|
+
|
|
87
|
+
Validation failures print API field details when the server returns them, for example:
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
Error 400: Validation failed
|
|
91
|
+
periodType: Invalid option: expected one of "monthly"|"weekly"|...
|
|
92
|
+
```
|
|
93
|
+
|
|
46
94
|
## Brain Usage
|
|
47
95
|
|
|
48
96
|
Brain usage should prefer the published `npx @klevar/portal-cli` entrypoint.
|
|
@@ -7,8 +7,8 @@ const budgetBody = [
|
|
|
7
7
|
export const capacityCommands = {
|
|
8
8
|
'capacity.list': { method: 'GET', path: '/api/admin/projects/:projectId/capacity-budgets', auth: 'apiKey', description: 'List project capacity budgets' },
|
|
9
9
|
'capacity.get': { method: 'GET', path: '/api/admin/capacity-budgets/:id', auth: 'apiKey', description: 'Get a capacity budget' },
|
|
10
|
-
'capacity.create': { method: 'POST', path: '/api/admin/projects/:projectId/capacity-budgets', auth: 'apiKey', description: 'Create a capacity budget', body: budgetBody },
|
|
11
|
-
'capacity.update': { method: 'PATCH', path: '/api/admin/capacity-budgets/:id', auth: 'apiKey', description: 'Update a capacity budget', body: budgetBody },
|
|
10
|
+
'capacity.create': { method: 'POST', path: '/api/admin/projects/:projectId/capacity-budgets', auth: 'apiKey', description: 'Create a capacity budget; periodType monthly|weekly, unitType hours|credits, visibility internal_only|client_visible_summary|client_visible_detail', body: budgetBody },
|
|
11
|
+
'capacity.update': { method: 'PATCH', path: '/api/admin/capacity-budgets/:id', auth: 'apiKey', description: 'Update a capacity budget; periodType monthly|weekly, unitType hours|credits, visibility internal_only|client_visible_summary|client_visible_detail', body: budgetBody },
|
|
12
12
|
'capacity.pause': { method: 'POST', path: '/api/admin/capacity-budgets/:id/pause', auth: 'apiKey', description: 'Pause a capacity budget' },
|
|
13
13
|
'capacity.resume': { method: 'POST', path: '/api/admin/capacity-budgets/:id/resume', auth: 'apiKey', description: 'Resume a capacity budget' },
|
|
14
14
|
'capacity.end': { method: 'POST', path: '/api/admin/capacity-budgets/:id/end', auth: 'apiKey', description: 'End a capacity budget' },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capacity.js","sourceRoot":"","sources":["../../commands/capacity.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,GAAG;IACjB,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,iBAAiB;IAC3E,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,SAAS,EAAE,gBAAgB;IACxE,qBAAqB,EAAE,SAAS,EAAE,cAAc,EAAE,eAAe;IACjE,eAAe,EAAE,mBAAmB,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW;CAC1E,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,eAAe,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,iDAAiD,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,+BAA+B,EAAE;IACzJ,cAAc,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,iCAAiC,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,uBAAuB,EAAE;IAChI,iBAAiB,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,iDAAiD,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"capacity.js","sourceRoot":"","sources":["../../commands/capacity.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,GAAG;IACjB,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,iBAAiB;IAC3E,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,SAAS,EAAE,gBAAgB;IACxE,qBAAqB,EAAE,SAAS,EAAE,cAAc,EAAE,eAAe;IACjE,eAAe,EAAE,mBAAmB,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW;CAC1E,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,eAAe,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,iDAAiD,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,+BAA+B,EAAE;IACzJ,cAAc,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,iCAAiC,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,uBAAuB,EAAE;IAChI,iBAAiB,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,iDAAiD,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oJAAoJ,EAAE,IAAI,EAAE,UAAU,EAAE;IACnS,iBAAiB,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,iCAAiC,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oJAAoJ,EAAE,IAAI,EAAE,UAAU,EAAE;IACpR,gBAAgB,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,uCAAuC,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,yBAAyB,EAAE;IAC3I,iBAAiB,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,wCAAwC,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,0BAA0B,EAAE;IAC9I,cAAc,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,qCAAqC,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,uBAAuB,EAAE;IACrI,iBAAiB,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,iCAAiC,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,0BAA0B,EAAE;IACzI,kBAAkB,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,iDAAiD,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,0BAA0B,EAAE,WAAW,EAAE,CAAC,QAAQ,CAAC,EAAE;IAChL,yBAAyB,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,+CAA+C,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,yBAAyB,EAAE,WAAW,EAAE,CAAC,QAAQ,CAAC,EAAE;IACpL,yBAAyB,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,yCAAyC,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,yBAAyB,EAAE,WAAW,EAAE,CAAC,QAAQ,CAAC,EAAE;IAC9K,iBAAiB,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,gDAAgD,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,yBAAyB,EAAE,WAAW,EAAE,CAAC,QAAQ,CAAC,EAAE;IAC7K,yBAAyB,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,kDAAkD,EAAE,IAAI,EAAE,aAAa,EAAE,WAAW,EAAE,yBAAyB,EAAE,WAAW,EAAE,CAAC,QAAQ,CAAC,EAAE;IAC5L,uBAAuB,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,gDAAgD,EAAE,IAAI,EAAE,aAAa,EAAE,WAAW,EAAE,+BAA+B,EAAE,WAAW,EAAE,CAAC,QAAQ,CAAC,EAAE;CACxK,CAAC"}
|
|
@@ -112,7 +112,7 @@ async function api(method, path, body, auth = 'apiKey') {
|
|
|
112
112
|
|
|
113
113
|
if (!res.ok) {
|
|
114
114
|
const err = await res.json().catch(() => ({ error: { message: res.statusText } }));
|
|
115
|
-
|
|
115
|
+
printApiError(res.status, err);
|
|
116
116
|
process.exit(1);
|
|
117
117
|
}
|
|
118
118
|
|
|
@@ -136,7 +136,7 @@ async function apiDownload(path, outputPath, auth = 'apiKey') {
|
|
|
136
136
|
|
|
137
137
|
if (!res.ok) {
|
|
138
138
|
const err = await res.json().catch(() => ({ error: { message: res.statusText } }));
|
|
139
|
-
|
|
139
|
+
printApiError(res.status, err);
|
|
140
140
|
process.exit(1);
|
|
141
141
|
}
|
|
142
142
|
|
|
@@ -208,7 +208,7 @@ async function apiMultipart(method, path, fields, filePaths) {
|
|
|
208
208
|
});
|
|
209
209
|
if (!res.ok) {
|
|
210
210
|
const err = await res.json().catch(() => ({ error: { message: res.statusText } }));
|
|
211
|
-
|
|
211
|
+
printApiError(res.status, err);
|
|
212
212
|
process.exit(1);
|
|
213
213
|
}
|
|
214
214
|
if (res.status === 204) return null;
|
|
@@ -223,6 +223,20 @@ async function streamToBuffer(stream) {
|
|
|
223
223
|
|
|
224
224
|
// ── Arg Parsing ─────────────────────────────────────────────────
|
|
225
225
|
|
|
226
|
+
function printApiError(status, payload) {
|
|
227
|
+
const error = payload?.error ?? payload;
|
|
228
|
+
console.error(`Error ${status}: ${error?.message || 'Unknown error'}`);
|
|
229
|
+
if (Array.isArray(error?.details) && error.details.length > 0) {
|
|
230
|
+
for (const detail of error.details) {
|
|
231
|
+
const field = detail.field || detail.path || 'unknown';
|
|
232
|
+
const message = detail.message || JSON.stringify(detail);
|
|
233
|
+
console.error(` ${field}: ${message}`);
|
|
234
|
+
}
|
|
235
|
+
} else if (payload && typeof payload === 'object' && !payload.error) {
|
|
236
|
+
console.error(JSON.stringify(payload, null, 2));
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
226
240
|
function parseArgs(args) {
|
|
227
241
|
const positional = [];
|
|
228
242
|
const flags = {};
|