@nickchristensen/cliftin 1.1.1 → 1.3.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,8 +5,8 @@ CLIftin: A read-only CLI for Liftin'
5
5
 
6
6
 
7
7
  [![oclif](https://img.shields.io/badge/cli-oclif-brightgreen.svg)](https://oclif.io)
8
- [![Version](https://img.shields.io/npm/v/@nickchristensen/cliftin.svg)](https://npmjs.org/package/cliftin)
9
- [![Downloads/week](https://img.shields.io/npm/dw/@nickchristensen/cliftin.svg)](https://npmjs.org/package/cliftin)
8
+ [![Version](https://img.shields.io/npm/v/@nickchristensen/cliftin.svg)](https://npmjs.org/package/@nickchristensen/cliftin)
9
+ [![Downloads/week](https://img.shields.io/npm/dw/@nickchristensen/cliftin.svg)](https://npmjs.org/package/@nickchristensen/cliftin)
10
10
 
11
11
 
12
12
  <!-- toc -->
@@ -47,7 +47,8 @@ USAGE
47
47
  * [`cliftin programs list`](#cliftin-programs-list)
48
48
  * [`cliftin programs show [SELECTOR]`](#cliftin-programs-show-selector)
49
49
  * [`cliftin workouts list`](#cliftin-workouts-list)
50
- * [`cliftin workouts show WORKOUTID`](#cliftin-workouts-show-workoutid)
50
+ * [`cliftin workouts next`](#cliftin-workouts-next)
51
+ * [`cliftin workouts show [WORKOUTID]`](#cliftin-workouts-show-workoutid)
51
52
 
52
53
  ## `cliftin exercises list`
53
54
 
@@ -72,7 +73,7 @@ DESCRIPTION
72
73
  List exercises
73
74
  ```
74
75
 
75
- _See code: [src/commands/exercises/list.ts](https://github.com/nickchristensen/cliftin/blob/v1.1.1/src/commands/exercises/list.ts)_
76
+ _See code: [src/commands/exercises/list.ts](https://github.com/nickchristensen/cliftin/blob/v1.3.0/src/commands/exercises/list.ts)_
76
77
 
77
78
  ## `cliftin exercises show SELECTOR`
78
79
 
@@ -106,7 +107,7 @@ DESCRIPTION
106
107
  Show one exercise detail and history
107
108
  ```
108
109
 
109
- _See code: [src/commands/exercises/show.ts](https://github.com/nickchristensen/cliftin/blob/v1.1.1/src/commands/exercises/show.ts)_
110
+ _See code: [src/commands/exercises/show.ts](https://github.com/nickchristensen/cliftin/blob/v1.3.0/src/commands/exercises/show.ts)_
110
111
 
111
112
  ## `cliftin help [COMMAND]`
112
113
 
@@ -143,7 +144,7 @@ DESCRIPTION
143
144
  List programs
144
145
  ```
145
146
 
146
- _See code: [src/commands/programs/list.ts](https://github.com/nickchristensen/cliftin/blob/v1.1.1/src/commands/programs/list.ts)_
147
+ _See code: [src/commands/programs/list.ts](https://github.com/nickchristensen/cliftin/blob/v1.3.0/src/commands/programs/list.ts)_
147
148
 
148
149
  ## `cliftin programs show [SELECTOR]`
149
150
 
@@ -151,14 +152,10 @@ Show one program hierarchy
151
152
 
152
153
  ```
153
154
  USAGE
154
- $ cliftin programs show [SELECTOR] [--json] [--active] [--current]
155
+ $ cliftin programs show [SELECTOR] [--json]
155
156
 
156
157
  ARGUMENTS
157
- [SELECTOR] program id or name
158
-
159
- FLAGS
160
- --active Show active program detail
161
- --current Alias for --active
158
+ [SELECTOR] program id or name (default: active program)
162
159
 
163
160
  GLOBAL FLAGS
164
161
  --json Format output as json.
@@ -167,7 +164,7 @@ DESCRIPTION
167
164
  Show one program hierarchy
168
165
  ```
169
166
 
170
- _See code: [src/commands/programs/show.ts](https://github.com/nickchristensen/cliftin/blob/v1.1.1/src/commands/programs/show.ts)_
167
+ _See code: [src/commands/programs/show.ts](https://github.com/nickchristensen/cliftin/blob/v1.3.0/src/commands/programs/show.ts)_
171
168
 
172
169
  ## `cliftin workouts list`
173
170
 
@@ -194,18 +191,35 @@ DESCRIPTION
194
191
  List workouts
195
192
  ```
196
193
 
197
- _See code: [src/commands/workouts/list.ts](https://github.com/nickchristensen/cliftin/blob/v1.1.1/src/commands/workouts/list.ts)_
194
+ _See code: [src/commands/workouts/list.ts](https://github.com/nickchristensen/cliftin/blob/v1.3.0/src/commands/workouts/list.ts)_
195
+
196
+ ## `cliftin workouts next`
197
+
198
+ Show the up-next routine from the active program
199
+
200
+ ```
201
+ USAGE
202
+ $ cliftin workouts next [--json]
203
+
204
+ GLOBAL FLAGS
205
+ --json Format output as json.
206
+
207
+ DESCRIPTION
208
+ Show the up-next routine from the active program
209
+ ```
210
+
211
+ _See code: [src/commands/workouts/next.ts](https://github.com/nickchristensen/cliftin/blob/v1.3.0/src/commands/workouts/next.ts)_
198
212
 
199
- ## `cliftin workouts show WORKOUTID`
213
+ ## `cliftin workouts show [WORKOUTID]`
200
214
 
201
215
  Show one workout with exercises and sets
202
216
 
203
217
  ```
204
218
  USAGE
205
- $ cliftin workouts show WORKOUTID [--json]
219
+ $ cliftin workouts show [WORKOUTID] [--json]
206
220
 
207
221
  ARGUMENTS
208
- WORKOUTID workout id
222
+ [WORKOUTID] workout id (default: latest workout)
209
223
 
210
224
  GLOBAL FLAGS
211
225
  --json Format output as json.
@@ -214,5 +228,5 @@ DESCRIPTION
214
228
  Show one workout with exercises and sets
215
229
  ```
216
230
 
217
- _See code: [src/commands/workouts/show.ts](https://github.com/nickchristensen/cliftin/blob/v1.1.1/src/commands/workouts/show.ts)_
231
+ _See code: [src/commands/workouts/show.ts](https://github.com/nickchristensen/cliftin/blob/v1.3.0/src/commands/workouts/show.ts)_
218
232
  <!-- commandsstop -->
@@ -5,9 +5,6 @@ export default class ProgramsShow extends Command {
5
5
  };
6
6
  static description: string;
7
7
  static enableJsonFlag: boolean;
8
- static flags: {
9
- active: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
- current: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
- };
8
+ static flags: {};
12
9
  run(): Promise<unknown | void>;
13
10
  }
@@ -1,4 +1,4 @@
1
- import { Args, Command, Flags } from '@oclif/core';
1
+ import { Args, Command } from '@oclif/core';
2
2
  import { closeDb, openDb } from '../../lib/db.js';
3
3
  import { serializeProgramDetailWithWeightUnits } from '../../lib/json-weight.js';
4
4
  import { renderTable } from '../../lib/output.js';
@@ -30,26 +30,16 @@ function buildProgramRows(weeks, unitLabel) {
30
30
  }
31
31
  export default class ProgramsShow extends Command {
32
32
  static args = {
33
- selector: Args.string({ description: 'program id or name', ignoreStdin: true, required: false }),
33
+ selector: Args.string({ description: 'program id or name (default: active program)', ignoreStdin: true, required: false }),
34
34
  };
35
35
  static description = 'Show one program hierarchy';
36
36
  static enableJsonFlag = true;
37
- static flags = {
38
- active: Flags.boolean({ description: 'Show active program detail' }),
39
- current: Flags.boolean({ description: 'Alias for --active' }),
40
- };
37
+ static flags = {};
41
38
  async run() {
42
- const { args, flags } = await this.parse(ProgramsShow);
39
+ const { args } = await this.parse(ProgramsShow);
43
40
  const context = openDb();
44
41
  try {
45
- const useActive = flags.active || flags.current;
46
- if (args.selector && useActive) {
47
- throw new Error('Use either a selector or --active/--current, not both.');
48
- }
49
- if (!args.selector && !useActive) {
50
- throw new Error('Provide a selector or use --active/--current.');
51
- }
52
- const programId = await resolveProgramSelector(context.db, args.selector, Boolean(useActive));
42
+ const programId = await resolveProgramSelector(context.db, args.selector, !args.selector);
53
43
  const detail = await getProgramDetail(context.db, programId);
54
44
  const unitPreference = await resolveProgramWeightUnit(context.db, detail.program.id);
55
45
  const unitLabel = weightUnitLabel(unitPreference);
@@ -57,7 +47,8 @@ export default class ProgramsShow extends Command {
57
47
  return serializeProgramDetailWithWeightUnits(detail, unitPreference);
58
48
  }
59
49
  this.log(`[${detail.program.id}] ${detail.program.name}`);
60
- this.log(`Active: ${detail.program.isActive} Template: ${detail.program.isTemplate}`);
50
+ this.log(`Active: ${detail.program.isActive}`);
51
+ this.log(`Template: ${detail.program.isTemplate}`);
61
52
  this.log('');
62
53
  const programRows = buildProgramRows(detail.weeks, unitLabel);
63
54
  const renderedTable = renderTable(programRows).replace(/^\n+/, '');
@@ -0,0 +1,6 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class WorkoutsNext extends Command {
3
+ static description: string;
4
+ static enableJsonFlag: boolean;
5
+ run(): Promise<unknown | void>;
6
+ }
@@ -0,0 +1,44 @@
1
+ import { Command } from '@oclif/core';
2
+ import { closeDb, openDb } from '../../lib/db.js';
3
+ import { toJsonErrorPayload } from '../../lib/json-error.js';
4
+ import { serializeNextWorkoutDetailWithWeightUnits } from '../../lib/json-weight.js';
5
+ import { renderTable } from '../../lib/output.js';
6
+ import { getNextWorkoutDetail } from '../../lib/repositories/workouts.js';
7
+ import { resolveProgramWeightUnit, weightUnitLabel } from '../../lib/units.js';
8
+ export default class WorkoutsNext extends Command {
9
+ static description = 'Show the up-next routine from the active program';
10
+ static enableJsonFlag = true;
11
+ async run() {
12
+ await this.parse(WorkoutsNext);
13
+ const context = openDb();
14
+ try {
15
+ const detail = await getNextWorkoutDetail(context.db);
16
+ const unitPreference = await resolveProgramWeightUnit(context.db, detail.program.id);
17
+ const unitLabel = weightUnitLabel(unitPreference);
18
+ if (this.jsonEnabled()) {
19
+ return serializeNextWorkoutDetailWithWeightUnits(detail, unitPreference);
20
+ }
21
+ this.log(`[${detail.routine.id}] ${detail.routine.name ?? 'Workout'}`);
22
+ this.log(`Program: ${detail.program.name}`);
23
+ this.log(`Week: ${detail.week.number}`);
24
+ for (const exercise of detail.routine.exercises) {
25
+ this.log('');
26
+ this.log(`[${exercise.id ?? exercise.exerciseConfigId}] ${exercise.name ?? '(unnamed)'}`);
27
+ this.log(renderTable(exercise.sets.map((set) => ({
28
+ reps: set.reps,
29
+ rpe: set.rpe,
30
+ timeSeconds: set.timeSeconds,
31
+ weight: set.weight === null ? null : `${set.weight} ${unitLabel}`,
32
+ }))));
33
+ }
34
+ }
35
+ catch (error) {
36
+ if (this.jsonEnabled())
37
+ return toJsonErrorPayload(error);
38
+ throw error;
39
+ }
40
+ finally {
41
+ await closeDb(context);
42
+ }
43
+ }
44
+ }
@@ -1,7 +1,7 @@
1
1
  import { Command } from '@oclif/core';
2
2
  export default class WorkoutsShow extends Command {
3
3
  static args: {
4
- workoutId: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
4
+ workoutId: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
5
5
  };
6
6
  static description: string;
7
7
  static enableJsonFlag: boolean;
@@ -3,7 +3,7 @@ import { format, isValid, parseISO } from 'date-fns';
3
3
  import { closeDb, openDb } from '../../lib/db.js';
4
4
  import { serializeWorkoutDetailWithWeightUnits } from '../../lib/json-weight.js';
5
5
  import { renderTable } from '../../lib/output.js';
6
- import { getWorkoutDetail } from '../../lib/repositories/workouts.js';
6
+ import { getWorkoutDetail, listWorkouts } from '../../lib/repositories/workouts.js';
7
7
  import { resolveGlobalWeightUnit, weightUnitLabel } from '../../lib/units.js';
8
8
  function formatDurationMinutes(durationSeconds) {
9
9
  if (durationSeconds === null)
@@ -20,7 +20,7 @@ function formatWorkoutDate(dateIso) {
20
20
  }
21
21
  export default class WorkoutsShow extends Command {
22
22
  static args = {
23
- workoutId: Args.string({ description: 'workout id', required: true }),
23
+ workoutId: Args.string({ description: 'workout id (default: latest workout)', ignoreStdin: true, required: false }),
24
24
  };
25
25
  static description = 'Show one workout with exercises and sets';
26
26
  static enableJsonFlag = true;
@@ -28,10 +28,17 @@ export default class WorkoutsShow extends Command {
28
28
  const { args } = await this.parse(WorkoutsShow);
29
29
  const context = openDb();
30
30
  try {
31
- if (!/^\d+$/.test(args.workoutId)) {
32
- throw new Error('Workout detail requires numeric workout id.');
31
+ if (args.workoutId !== undefined && !/^\d+$/.test(args.workoutId)) {
32
+ throw new Error('Workout id must be numeric.');
33
33
  }
34
- const detail = await getWorkoutDetail(context.db, Number(args.workoutId));
34
+ const workoutId = args.workoutId
35
+ ? Number(args.workoutId)
36
+ : await listWorkouts(context.db, { limit: 1 }).then((rows) => {
37
+ if (rows.length === 0)
38
+ throw new Error('No workouts found.');
39
+ return rows[0].id;
40
+ });
41
+ const detail = await getWorkoutDetail(context.db, workoutId);
35
42
  const unitPreference = await resolveGlobalWeightUnit(context.db);
36
43
  const unitLabel = weightUnitLabel(unitPreference);
37
44
  if (this.jsonEnabled()) {
package/dist/lib/db.d.ts CHANGED
@@ -60,6 +60,7 @@ export interface DatabaseSchema {
60
60
  ZNAME: null | string;
61
61
  ZPERIOD: null | number;
62
62
  ZSOFTDELETED: null | number;
63
+ ZUPNEXT: null | number;
63
64
  ZWORKOUTPLAN: null | number;
64
65
  };
65
66
  ZSETCONFIGURATION: {
@@ -1,7 +1,8 @@
1
- import { ExerciseHistoryRow, ProgramDetailTree, WorkoutDetail } from './types.js';
1
+ import { ExerciseHistoryRow, NextWorkoutDetail, ProgramDetailTree, WorkoutDetail } from './types.js';
2
2
  import { UnitPreference, withWeightUnit } from './units.js';
3
3
  export declare function serializeExerciseHistoryRowsWithWeightUnits(rows: ExerciseHistoryRow[], unitPreference: UnitPreference): Array<Omit<ExerciseHistoryRow, 'topWeight'> & {
4
4
  topWeight: ReturnType<typeof withWeightUnit>;
5
5
  }>;
6
6
  export declare function serializeProgramDetailWithWeightUnits(detail: ProgramDetailTree, unitPreference: UnitPreference): unknown;
7
+ export declare function serializeNextWorkoutDetailWithWeightUnits(detail: NextWorkoutDetail, unitPreference: UnitPreference): unknown;
7
8
  export declare function serializeWorkoutDetailWithWeightUnits(detail: WorkoutDetail, unitPreference: UnitPreference): unknown;
@@ -24,6 +24,22 @@ export function serializeProgramDetailWithWeightUnits(detail, unitPreference) {
24
24
  })),
25
25
  };
26
26
  }
27
+ export function serializeNextWorkoutDetailWithWeightUnits(detail, unitPreference) {
28
+ return {
29
+ ...detail,
30
+ routine: {
31
+ ...detail.routine,
32
+ exercises: detail.routine.exercises.map((exercise) => ({
33
+ ...exercise,
34
+ plannedWeight: withWeightUnit(exercise.plannedWeight, unitPreference),
35
+ sets: exercise.sets.map((set) => ({
36
+ ...set,
37
+ weight: withWeightUnit(set.weight, unitPreference),
38
+ })),
39
+ })),
40
+ },
41
+ };
42
+ }
27
43
  export function serializeWorkoutDetailWithWeightUnits(detail, unitPreference) {
28
44
  return {
29
45
  ...detail,
@@ -54,7 +54,7 @@ export async function resolveProgramSelector(db, selector, activeOnly) {
54
54
  return fallbackRows[0].id;
55
55
  }
56
56
  if (!selector)
57
- throw new Error('Program selector is required unless --active/--current is set.');
57
+ throw new Error('Program selector is required.');
58
58
  const programId = await resolveIdOrName(db, 'ZWORKOUTPLAN', selector);
59
59
  const nonDeleted = await db
60
60
  .selectFrom('ZWORKOUTPLAN')
@@ -1,6 +1,6 @@
1
1
  import { Kysely } from 'kysely';
2
2
  import { DatabaseSchema } from '../db.js';
3
- import { WorkoutDetail, WorkoutSummary } from '../types.js';
3
+ import { NextWorkoutDetail, WorkoutDetail, WorkoutSummary } from '../types.js';
4
4
  export type WorkoutFilters = {
5
5
  from?: string;
6
6
  limit?: number;
@@ -9,5 +9,6 @@ export type WorkoutFilters = {
9
9
  routine?: string;
10
10
  to?: string;
11
11
  };
12
+ export declare function getNextWorkoutDetail(db: Kysely<DatabaseSchema>): Promise<NextWorkoutDetail>;
12
13
  export declare function listWorkouts(db: Kysely<DatabaseSchema>, filters: WorkoutFilters): Promise<WorkoutSummary[]>;
13
14
  export declare function getWorkoutDetail(db: Kysely<DatabaseSchema>, workoutId: number): Promise<WorkoutDetail>;
@@ -2,10 +2,50 @@ import { formatExerciseDisplayName } from '../names.js';
2
2
  import { normalizeRpe } from '../rpe.js';
3
3
  import { appleSecondsToIso, dateRangeToAppleSeconds } from '../time.js';
4
4
  import { convertKgToDisplayVolume, convertKgToDisplayWeight, resolveGlobalWeightUnit } from '../units.js';
5
+ import { getProgramDetail, resolveProgramSelector } from './programs.js';
5
6
  import { resolveIdOrName } from './selectors.js';
6
7
  function asBool(value) {
7
8
  return value === 1;
8
9
  }
10
+ export async function getNextWorkoutDetail(db) {
11
+ const programId = await resolveProgramSelector(db, undefined, true);
12
+ const programDetail = await getProgramDetail(db, programId);
13
+ const nextRoutines = await db
14
+ .selectFrom('ZROUTINE as r')
15
+ .leftJoin('ZPERIOD as p', 'p.Z_PK', 'r.ZPERIOD')
16
+ .select(['r.Z_PK as id', 'r.ZPERIOD as weekId'])
17
+ .where('r.ZUPNEXT', '=', 1)
18
+ .where('r.ZSOFTDELETED', 'is not', 1)
19
+ .where((eb) => eb.or([eb('p.ZWORKOUTPLAN', '=', programId), eb('r.ZWORKOUTPLAN', '=', programId)]))
20
+ .orderBy('p.Z_FOK_WORKOUTPLAN', 'asc')
21
+ .orderBy('r.Z_FOK_PERIOD', 'asc')
22
+ .orderBy('r.Z_PK', 'asc')
23
+ .execute();
24
+ if (nextRoutines.length === 0) {
25
+ throw new Error(`No up-next routine found for active program ${programDetail.program.name}.`);
26
+ }
27
+ if (nextRoutines.length > 1) {
28
+ throw new Error(`Expected exactly one up-next routine for active program ${programDetail.program.name}. Found ${nextRoutines.length}.`);
29
+ }
30
+ const nextRoutine = nextRoutines[0];
31
+ const weekIndex = programDetail.weeks.findIndex((week) => week.id === nextRoutine.weekId);
32
+ if (weekIndex === -1) {
33
+ throw new Error(`Up-next routine ${nextRoutine.id} is linked to unknown week ${nextRoutine.weekId}.`);
34
+ }
35
+ const week = programDetail.weeks[weekIndex];
36
+ const routine = week.routines.find((entry) => entry.id === nextRoutine.id);
37
+ if (!routine) {
38
+ throw new Error(`Up-next routine ${nextRoutine.id} was not found in active program detail.`);
39
+ }
40
+ return {
41
+ program: programDetail.program,
42
+ routine,
43
+ week: {
44
+ id: week.id,
45
+ number: weekIndex + 1,
46
+ },
47
+ };
48
+ }
9
49
  export async function listWorkouts(db, filters) {
10
50
  const dateRange = dateRangeToAppleSeconds({ from: filters.from, on: filters.on, to: filters.to });
11
51
  let query = db
@@ -73,7 +113,12 @@ export async function getWorkoutDetail(db, workoutId) {
73
113
  .selectFrom('ZEXERCISERESULT as er')
74
114
  .leftJoin('ZEXERCISECONFIGURATION as ec', 'ec.Z_PK', 'er.ZCONFIGURATION')
75
115
  .leftJoin('ZEXERCISEINFORMATION as ei', 'ei.Z_PK', 'ec.ZINFORMATION')
76
- .select(['er.Z_PK as exerciseResultId', 'ei.Z_PK as exerciseId', 'ei.ZISUSERCREATED as isUserCreated', 'ei.ZNAME as exerciseName'])
116
+ .select([
117
+ 'er.Z_PK as exerciseResultId',
118
+ 'ei.Z_PK as exerciseId',
119
+ 'ei.ZISUSERCREATED as isUserCreated',
120
+ 'ei.ZNAME as exerciseName',
121
+ ])
77
122
  .where('er.ZWORKOUT', '=', workoutId)
78
123
  .orderBy('er.Z_FOK_WORKOUT', 'asc')
79
124
  .orderBy('er.Z_PK', 'asc')
@@ -68,6 +68,14 @@ export type WorkoutDetail = {
68
68
  program: null | string;
69
69
  routine: null | string;
70
70
  };
71
+ export type NextWorkoutDetail = {
72
+ program: ProgramSummary;
73
+ routine: ProgramRoutine;
74
+ week: {
75
+ id: number;
76
+ number: number;
77
+ };
78
+ };
71
79
  export type ExerciseSummary = {
72
80
  equipment: null | string;
73
81
  id: number;
@@ -210,7 +210,7 @@
210
210
  "aliases": [],
211
211
  "args": {
212
212
  "selector": {
213
- "description": "program id or name",
213
+ "description": "program id or name (default: active program)",
214
214
  "name": "selector",
215
215
  "required": false
216
216
  }
@@ -223,18 +223,6 @@
223
223
  "name": "json",
224
224
  "allowNo": false,
225
225
  "type": "boolean"
226
- },
227
- "active": {
228
- "description": "Show active program detail",
229
- "name": "active",
230
- "allowNo": false,
231
- "type": "boolean"
232
- },
233
- "current": {
234
- "description": "Alias for --active",
235
- "name": "current",
236
- "allowNo": false,
237
- "type": "boolean"
238
226
  }
239
227
  },
240
228
  "hasDynamicHelp": false,
@@ -346,13 +334,42 @@
346
334
  "list.js"
347
335
  ]
348
336
  },
337
+ "workouts:next": {
338
+ "aliases": [],
339
+ "args": {},
340
+ "description": "Show the up-next routine from the active program",
341
+ "flags": {
342
+ "json": {
343
+ "description": "Format output as json.",
344
+ "helpGroup": "GLOBAL",
345
+ "name": "json",
346
+ "allowNo": false,
347
+ "type": "boolean"
348
+ }
349
+ },
350
+ "hasDynamicHelp": false,
351
+ "hiddenAliases": [],
352
+ "id": "workouts:next",
353
+ "pluginAlias": "@nickchristensen/cliftin",
354
+ "pluginName": "@nickchristensen/cliftin",
355
+ "pluginType": "core",
356
+ "strict": true,
357
+ "enableJsonFlag": true,
358
+ "isESM": true,
359
+ "relativePath": [
360
+ "dist",
361
+ "commands",
362
+ "workouts",
363
+ "next.js"
364
+ ]
365
+ },
349
366
  "workouts:show": {
350
367
  "aliases": [],
351
368
  "args": {
352
369
  "workoutId": {
353
- "description": "workout id",
370
+ "description": "workout id (default: latest workout)",
354
371
  "name": "workoutId",
355
- "required": true
372
+ "required": false
356
373
  }
357
374
  },
358
375
  "description": "Show one workout with exercises and sets",
@@ -382,5 +399,5 @@
382
399
  ]
383
400
  }
384
401
  },
385
- "version": "1.1.1"
402
+ "version": "1.3.0"
386
403
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nickchristensen/cliftin",
3
3
  "description": "CLIftin: A read-only CLI for Liftin'",
4
- "version": "1.1.1",
4
+ "version": "1.3.0",
5
5
  "author": "Nick Christensen",
6
6
  "bin": {
7
7
  "cliftin": "./bin/run.js"