@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 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,0BAA0B,EAAE,IAAI,EAAE,UAAU,EAAE;IACzK,iBAAiB,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,iCAAiC,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,0BAA0B,EAAE,IAAI,EAAE,UAAU,EAAE;IAC1J,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"}
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
- console.error(`Error ${res.status}: ${err.error?.message || 'Unknown error'}`);
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
- console.error(`Error ${res.status}: ${err.error?.message || 'Unknown error'}`);
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
- console.error(`Error ${res.status}: ${err.error?.message || 'Unknown error'}`);
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 = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@klevar/portal-cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "First-class npm CLI for the Klevar Client Management Portal",
5
5
  "type": "module",
6
6
  "bin": {