@zinn-dev/cli 0.10.0 → 0.11.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
@@ -124,7 +124,7 @@ Use `task relation create --help` to discover types.
124
124
 
125
125
  ## Edit tasks
126
126
 
127
- Edit a task's title, description, or labels:
127
+ Edit a task's title, description, priority, or labels:
128
128
 
129
129
  ```sh
130
130
  zinn task edit MDR-1 --title "Meet the quarterly refinement quota"
@@ -196,3 +196,15 @@ zinn task move --help
196
196
  The short `-h` form works in the same positions.
197
197
 
198
198
  Running `zinn` without a command shows help
199
+
200
+ ## Task priority
201
+
202
+ Priority is optional: `low`, `medium`, `high`, or `urgent`. New tasks have no assigned priority by default.
203
+
204
+ ```sh
205
+ zinn task create MDR --title "Review the numbers" --priority high
206
+ zinn task edit MDR-1 --priority urgent
207
+ zinn task edit MDR-1 --priority none
208
+ ```
209
+
210
+ Use `none` to clear priority. Omitting `--priority` on edits preserves it. Assigned priorities appear in task list and view output; board ordering remains unchanged.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zinn-dev/cli",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "A kanban workflow in the terminal.",
5
5
  "license": "MIT",
6
6
  "bugs": {
@@ -42,6 +42,6 @@
42
42
  "access": "public"
43
43
  },
44
44
  "dependencies": {
45
- "@zinn-dev/core": "0.10.0"
45
+ "@zinn-dev/core": "0.11.0"
46
46
  }
47
47
  }
@@ -6,6 +6,8 @@ import { task, project, column } from "@zinn-dev/core";
6
6
  import { quit, validatePositionalCount, validateUniqueOptions } from "../lib";
7
7
  import { formatRelations, relationRouter } from "./relation-router";
8
8
 
9
+ // TODO: a CLI row formatter that accepts text columns and joins them with " | " would be useful
10
+ // Reuse it across task list/view and other command output in a separate change.
9
11
  function formatTask(
10
12
  taskMatch: ReturnType<typeof task.getByKey>,
11
13
  options: { showsStatus?: boolean } = {},
@@ -17,11 +19,12 @@ function formatTask(
17
19
  : "";
18
20
  const description = taskMatch.description == null ? "" : ` | ${taskMatch.description}`;
19
21
 
22
+ const priority = taskMatch.priority == null ? "" : ` | Priority: ${taskMatch.priority}`;
20
23
  const labels = task.label.getAll(taskKey);
21
24
  const labelText =
22
25
  labels.length === 0 ? "" : ` | Labels: ${labels.map((label) => label.name).join(", ")}`;
23
26
 
24
- return `${taskKey}${status} | ${taskColumn.name} | ${taskMatch.title}${description}${labelText}`;
27
+ return `${taskKey}${status} | ${taskColumn.name} | ${taskMatch.title}${description}${priority}${labelText}`;
25
28
  }
26
29
 
27
30
  export const taskRouter = {
@@ -32,6 +35,7 @@ export const taskRouter = {
32
35
  options: {
33
36
  title: { type: "string" },
34
37
  description: { type: "string" },
38
+ priority: { type: "string" },
35
39
  "add-label": { type: "string", multiple: true },
36
40
  "remove-label": { type: "string", multiple: true },
37
41
  },
@@ -53,12 +57,13 @@ export const taskRouter = {
53
57
  const hasEditFlags =
54
58
  values.title !== undefined ||
55
59
  values.description !== undefined ||
60
+ values.priority !== undefined ||
56
61
  values["add-label"] !== undefined ||
57
62
  values["remove-label"] !== undefined;
58
63
 
59
64
  if (!hasEditFlags) {
60
65
  quit(
61
- "Provide at least one edit flag: --title, --description, --add-label, or --remove-label",
66
+ "Provide at least one edit flag: --title, --description, --priority, --add-label, or --remove-label",
62
67
  );
63
68
  }
64
69
 
@@ -66,15 +71,17 @@ export const taskRouter = {
66
71
  taskKey,
67
72
  title: values.title,
68
73
  description: values.description,
74
+ priority: parsePriority(values.priority),
69
75
  addLabelNames: values["add-label"],
70
76
  removeLabelNames: values["remove-label"],
71
77
  });
72
78
 
73
79
  console.info(formatTask(editedTask));
74
80
  },
75
- help: `Usage: zinn task edit <task-key> [--title <text>] [--description <text>] [--add-label <name>] [--remove-label <name>]
81
+ help: `Usage: zinn task edit <task-key> [--title <text>] [--description <text>] [--priority <low|medium|high|urgent|none>] [--add-label <name>] [--remove-label <name>]
76
82
 
77
83
  Change the supplied fields and preserve everything else.
84
+ Use --priority none to clear priority.
78
85
  Provide at least one edit flag. Use --description "" for an empty description.
79
86
 
80
87
  Repeat --add-label or --remove-label for multiple existing labels.
@@ -95,6 +102,7 @@ Example: zinn task edit MDR-1 --title "Meet the quarterly refinement quota"`,
95
102
  options: {
96
103
  title: { type: "string" },
97
104
  description: { type: "string" },
105
+ priority: { type: "string" },
98
106
  label: { type: "string", multiple: true },
99
107
  },
100
108
  allowPositionals: true,
@@ -105,7 +113,11 @@ Example: zinn task edit MDR-1 --title "Meet the quarterly refinement quota"`,
105
113
  if (projectKey == null) {
106
114
  quit("A task needs to belong to a project");
107
115
  }
108
- validatePositionalCount(positionals, 1, "Only one project key can be specified; use --title and --description");
116
+ validatePositionalCount(
117
+ positionals,
118
+ 1,
119
+ "Only one project key can be specified; use --title and --description",
120
+ );
109
121
  if (values.title === undefined) {
110
122
  quit("A task needs at least a title: use --title");
111
123
  }
@@ -118,13 +130,15 @@ Example: zinn task edit MDR-1 --title "Meet the quarterly refinement quota"`,
118
130
  project_id: projectMatch.id,
119
131
  title: values.title,
120
132
  description: values.description ?? null,
133
+ priority: parsePriority(values.priority),
121
134
  labelNames: values.label,
122
135
  });
123
136
  console.info(formatTask(createdTask));
124
137
  },
125
- help: `Usage: zinn task create <project-key> --title <text> [--description <text>] [--label <name>]
138
+ help: `Usage: zinn task create <project-key> --title <text> [--description <text>] [--priority <low|medium|high|urgent|none>] [--label <name>]
126
139
 
127
140
  Create a task in the project's first column.
141
+ Priority defaults to none (unassigned).
128
142
  Repeat --label to attach multiple existing labels. Unknown labels are errors.
129
143
  Titles cannot be blank. Use --title="--example" for text beginning with a dash.
130
144
 
@@ -163,6 +177,7 @@ Example: zinn task create MDR --title "Refine the numbers" --description "Meet t
163
177
  status: t.archived_at == null ? "Active" : "Archived",
164
178
  title: t.title,
165
179
  description: t.description,
180
+ priority: t.priority,
166
181
  column: taskColumn.name,
167
182
  };
168
183
  });
@@ -182,7 +197,8 @@ Example: zinn task create MDR --title "Refine the numbers" --description "Meet t
182
197
  // TODO: console output formatting for standardizied output
183
198
  const status = showsAll ? ` | ${t.status.padEnd(longestStatusLength)}` : "";
184
199
  const description = t.description == null ? "" : ` | ${t.description}`;
185
- return `${t.id.padEnd(longestIdLength)}${status} | ${t.column} | ${t.title}${description}`;
200
+ const priority = t.priority == null ? "" : ` | Priority: ${t.priority}`;
201
+ return `${t.id.padEnd(longestIdLength)}${status} | ${t.column} | ${t.title}${description}${priority}`;
186
202
  })
187
203
  .join("\n"),
188
204
  );
@@ -212,7 +228,7 @@ Example: zinn task list MDR --all`,
212
228
  },
213
229
  help: `Usage: zinn task view <task-key>
214
230
 
215
- Show a task with its current column, description, labels, and relations.
231
+ Show a task with its current column, description, priority, labels, and relations.
216
232
 
217
233
  Example: zinn task view MDR-1`,
218
234
  },
@@ -388,3 +404,19 @@ function parseTaskLabelArgs(args: string[]) {
388
404
  }
389
405
  return { taskKey: positionals[0]!, labelNames: positionals.slice(1) };
390
406
  }
407
+
408
+ function parsePriority(value: string | undefined) {
409
+ switch (value) {
410
+ case undefined:
411
+ return undefined;
412
+ case "none":
413
+ return null;
414
+ case "low":
415
+ case "medium":
416
+ case "high":
417
+ case "urgent":
418
+ return value;
419
+ default:
420
+ quit("Priority must be low, medium, high, urgent, or none");
421
+ }
422
+ }