@fleetkeep/cli 0.4.0 → 0.5.0

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
@@ -5,6 +5,40 @@ API. Friendly commands cover common vehicle and spreadsheet work. The allowliste
5
5
  command covers equipment, maintenance, defects, walkarounds, files, reminders, contacts, bookings,
6
6
  tolls, tracking, guidance and exports without opening arbitrary or unpublished paths.
7
7
 
8
+ ## Shared jobs and running costs
9
+
10
+ Friendly commands return JSON, including missing-data and stale-tracking fields:
11
+
12
+ ```sh
13
+ fleetkeep costs list --from 2026-09-01 --to 2026-09-30
14
+ fleetkeep costs record --data-file expense.json
15
+ fleetkeep drivers activity --search JOB-42
16
+ fleetkeep tracking list
17
+ fleetkeep tracking route <vehicle-id> --period 7d
18
+ ```
19
+
20
+ Driver activity returns up to 100 journeys and 100 inspections from the company's
21
+ central record. Search filters journeys by job reference, driver or registration;
22
+ inspections remain the latest 100. The activity endpoint must be deployed before
23
+ using this command. Route history requires a supported connected tracker.
24
+ Expense files use the fields below; keep the same UUID and body when retrying.
25
+
26
+ `fleetkeep jobs list --search JOB-42` finds company jobs. Use
27
+ `fleetkeep jobs save JOB-42 --title "Depot installation"` to create or update a reference,
28
+ and `fleetkeep jobs close <job-id>` or `reopen <job-id>` to change its availability.
29
+ Closing a job preserves its journey history. These owner operations need an active Fleet plan.
30
+
31
+ `fleetkeep api call getRunningCosts --query from=2026-09-01 --query to=2026-09-30`
32
+ returns recorded GBP costs and missing-data flags. `recordFleetExpense` accepts a JSON body
33
+ with `id` (UUID), `vehicleId`, `incurredOn`, `category`, `amount` (GBP decimal string) and
34
+ `description`. Reuse the UUID and identical body on retries. Dates span up to one year.
35
+ Supported categories are fuel, insurance, repair, parking and other. Negative amounts record
36
+ refunds or corrections. Service costs and recorded GBP tolls are included separately, so do
37
+ not enter them again. Account JSON exports include jobs, journeys and additional costs.
38
+
39
+ Xero authorisation and bill review take place in the web portal. Saved SHVL grants and
40
+ credentials are not transferred between products or customer workspaces.
41
+
8
42
  ## Safety model
9
43
 
10
44
  - `api operations` is generated as a fixed allowlist of the published OpenAPI operation IDs.
package/fleetkeep.mjs CHANGED
@@ -21,9 +21,18 @@ Usage:
21
21
  fleetkeep vehicles delete <vehicle-id> [--confirmation <server-token>] [--json]
22
22
  fleetkeep vehicles bulk-add <registration>... [--json]
23
23
  fleetkeep drivers list [--json]
24
+ fleetkeep drivers activity [--search <job-driver-registration>] [--json]
25
+ fleetkeep costs list [--from <YYYY-MM-DD>] [--to <YYYY-MM-DD>] [--json]
26
+ fleetkeep costs record --data-file <expense.json>
27
+ fleetkeep tracking list [--json]
28
+ fleetkeep tracking route <vehicle-id> [--period <period>] [--json]
24
29
  fleetkeep drivers invite <email> --name <name> [--json]
25
30
  fleetkeep drivers resend <driver-id> [--json]
26
31
  fleetkeep drivers revoke <driver-id> [--json]
32
+ fleetkeep jobs list [--search <reference>] [--json]
33
+ fleetkeep jobs save <reference> --title <title> [--json]
34
+ fleetkeep jobs close <job-id> [--json]
35
+ fleetkeep jobs reopen <job-id> [--json]
27
36
  fleetkeep import preview <file.csv|file.xlsx> [--json]
28
37
  fleetkeep import apply <file.csv|file.xlsx> --confirm <digest> [--idempotency-key <key>] [--json]
29
38
  fleetkeep api operations [--json]
@@ -293,6 +302,46 @@ async function main() {
293
302
  return;
294
303
  }
295
304
 
305
+ if (args[0] === 'costs' && args[1] === 'list') {
306
+ const query = [];
307
+ for (const name of ['from', 'to']) {
308
+ const value = option(args, `--${name}`);
309
+ if (value) query.push('--query', `${name}=${value}`);
310
+ }
311
+ await runApiCommand(['call', 'getRunningCosts', ...query]);
312
+ return;
313
+ }
314
+ if (args[0] === 'costs' && args[1] === 'record') {
315
+ const file = option(args, '--data-file');
316
+ if (!file) throw new Error('--data-file is required. Reuse the expense UUID on retries.');
317
+ await runApiCommand(['call', 'recordFleetExpense', '--data-file', file]);
318
+ return;
319
+ }
320
+ if (args[0] === 'tracking' && args[1] === 'list') {
321
+ await runApiCommand(['call', 'listTrackingSnapshots']);
322
+ return;
323
+ }
324
+ if (args[0] === 'tracking' && args[1] === 'route') {
325
+ if (!args[2] || args[2].startsWith('--')) throw new Error('A vehicle ID is required.');
326
+ const period = option(args, '--period');
327
+ await runApiCommand([
328
+ 'call',
329
+ 'getWexRouteHistory',
330
+ '--path',
331
+ `vehicleId=${args[2]}`,
332
+ ...(period ? ['--query', `period=${period}`] : [])
333
+ ]);
334
+ return;
335
+ }
336
+ if (args[0] === 'drivers' && args[1] === 'activity') {
337
+ const payload = await request(
338
+ `/api/v1/drivers/activity?q=${encodeURIComponent(option(args, '--search') || '')}`,
339
+ {}
340
+ );
341
+ process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
342
+ return;
343
+ }
344
+
296
345
  if (args[0] === 'auth' && args[1] === 'login') {
297
346
  await login({ noBrowser: args.includes('--no-browser') });
298
347
  return;
@@ -409,6 +458,30 @@ async function main() {
409
458
  return;
410
459
  }
411
460
 
461
+ if (args[0] === 'jobs' && ['list', 'save', 'close', 'reopen'].includes(args[1])) {
462
+ const action = args[1];
463
+ let payload;
464
+ if (action === 'list') {
465
+ payload = await request(
466
+ `/api/v1/jobs?q=${encodeURIComponent(option(args, '--search') || '')}`,
467
+ {}
468
+ );
469
+ } else {
470
+ if (!args[2] || args[2].startsWith('--'))
471
+ throw new Error('A job reference or ID is required.');
472
+ if (action === 'save' && !option(args, '--title')) throw new Error('--title is required.');
473
+ payload = await request('/api/v1/jobs', {
474
+ method: 'POST',
475
+ body:
476
+ action === 'save'
477
+ ? { action: 'save', reference: args[2], title: option(args, '--title') }
478
+ : { action: 'status', id: args[2], status: action === 'close' ? 'closed' : 'active' }
479
+ });
480
+ }
481
+ process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
482
+ return;
483
+ }
484
+
412
485
  if (args[0] === 'drivers' && args[1] === 'list') {
413
486
  const payload = await request('/api/v1/drivers', {});
414
487
  if (jsonOutput) process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
package/operations.mjs CHANGED
@@ -1,5 +1,17 @@
1
1
  /** @type {Array<[string, string, string, string, Record<string, unknown>?]>} */
2
2
  const definitions = [
3
+ ['importProviderJobs', 'POST', '/api/v1/jobs/import', 'operations:write'],
4
+ ['listFleetJobs', 'GET', '/api/v1/jobs', 'operations:read', { query: ['q'] }],
5
+ ['saveFleetJob', 'POST', '/api/v1/jobs', 'operations:write'],
6
+ ['getRunningCosts', 'GET', '/api/v1/costs', 'operations:read', { query: ['from', 'to'] }],
7
+ ['recordFleetExpense', 'POST', '/api/v1/costs', 'operations:write'],
8
+ [
9
+ 'listDriverJobs',
10
+ 'GET',
11
+ '/api/v1/driver-workspace/{id}/jobs',
12
+ 'operations:read',
13
+ { query: ['q'] }
14
+ ],
3
15
  ['listVehicles', 'GET', '/api/v1/vehicles', 'vehicles:read'],
4
16
  ['addVehicle', 'POST', '/api/v1/vehicles', 'vehicles:write'],
5
17
  ['getVehicle', 'GET', '/api/v1/vehicles/{id}', 'vehicles:read'],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fleetkeep/cli",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Operate every published Fleetkeep API workflow with guarded writes and machine-readable output",
5
5
  "type": "module",
6
6
  "bin": {