@basementuniverse/kanbn 2.0.0 → 2.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.
Files changed (100) hide show
  1. package/README.md +3 -1
  2. package/coverage/tmp/coverage-916017-1788028598821-0.json +1 -0
  3. package/coverage/tmp/{coverage-214293-1787777184569-0.json → coverage-916018-1788028597179-0.json} +1 -1
  4. package/coverage/tmp/coverage-916036-1788028598796-0.json +1 -0
  5. package/docs/actions.md +337 -0
  6. package/docs/advanced-configuration.md +55 -0
  7. package/docs/commands/add.txt +17 -1
  8. package/docs/commands/archive.txt +11 -0
  9. package/docs/commands/board.txt +9 -0
  10. package/docs/commands/boards.txt +34 -0
  11. package/docs/commands/burndown.txt +7 -0
  12. package/docs/commands/comment.txt +13 -1
  13. package/docs/commands/contributors.txt +58 -0
  14. package/docs/commands/edit.txt +18 -1
  15. package/docs/commands/find.txt +39 -1
  16. package/docs/commands/gantt.txt +6 -0
  17. package/docs/commands/help.txt +2 -0
  18. package/docs/commands/history.txt +6 -0
  19. package/docs/commands/init.txt +13 -0
  20. package/docs/commands/move.txt +26 -0
  21. package/docs/commands/remove.txt +22 -1
  22. package/docs/commands/rename.txt +5 -0
  23. package/docs/commands/restore.txt +12 -0
  24. package/docs/commands/sort.txt +23 -0
  25. package/docs/commands/sprint.txt +9 -0
  26. package/docs/commands/status.txt +10 -1
  27. package/docs/commands/task.txt +9 -0
  28. package/docs/commands/validate.txt +29 -1
  29. package/docs/contributors.md +145 -0
  30. package/docs/filtering-and-sorting.md +60 -3
  31. package/docs/index-structure.md +145 -11
  32. package/docs/index.md +6 -2
  33. package/docs/multiple-boards.md +259 -0
  34. package/docs/quick-start.md +21 -1
  35. package/docs/task-structure.md +31 -3
  36. package/example/README.md +23 -0
  37. package/example/advanced/kanbn.yml +65 -0
  38. package/example/boards/.kanbn/design.md +31 -0
  39. package/example/boards/.kanbn/index.md +44 -0
  40. package/example/boards/.kanbn/tasks/add-usage-alert-emails.md +19 -0
  41. package/example/boards/.kanbn/tasks/build-tenant-settings-page.md +43 -0
  42. package/example/boards/.kanbn/tasks/create-organization-switcher.md +44 -0
  43. package/example/boards/.kanbn/tasks/design-onboarding-checklist.md +22 -0
  44. package/example/boards/.kanbn/tasks/refresh-marketing-site.md +28 -0
  45. package/example/boards/.kanbn/tasks/ship-billing-portal.md +29 -0
  46. package/package.json +9 -7
  47. package/routes/add.json +40 -12
  48. package/routes/archive.json +14 -2
  49. package/routes/board.json +11 -3
  50. package/routes/boards.json +30 -0
  51. package/routes/burndown.json +23 -7
  52. package/routes/comment.json +19 -5
  53. package/routes/contributors.json +18 -0
  54. package/routes/edit.json +37 -11
  55. package/routes/find.json +37 -12
  56. package/routes/gantt.json +20 -6
  57. package/routes/history.json +39 -25
  58. package/routes/init.json +3 -1
  59. package/routes/move.json +24 -6
  60. package/routes/remove.json +18 -3
  61. package/routes/rename.json +11 -3
  62. package/routes/restore.json +14 -2
  63. package/routes/sort.json +40 -11
  64. package/routes/sprint.json +14 -4
  65. package/routes/status.json +23 -7
  66. package/routes/task.json +10 -2
  67. package/routes/validate.json +18 -5
  68. package/skills/kanbn-plan/SKILL.md +10 -1
  69. package/skills/kanbn-replan/SKILL.md +6 -1
  70. package/src/actions.js +904 -0
  71. package/src/board.js +25 -2
  72. package/src/controller/add.js +72 -55
  73. package/src/controller/archive.js +9 -4
  74. package/src/controller/board.js +21 -13
  75. package/src/controller/boards.js +140 -0
  76. package/src/controller/burndown.js +14 -7
  77. package/src/controller/comment.js +13 -6
  78. package/src/controller/contributors.js +166 -0
  79. package/src/controller/edit.js +48 -18
  80. package/src/controller/find.js +87 -13
  81. package/src/controller/gantt.js +13 -6
  82. package/src/controller/history.js +13 -6
  83. package/src/controller/init.js +39 -4
  84. package/src/controller/move.js +153 -25
  85. package/src/controller/remove.js +73 -13
  86. package/src/controller/rename.js +8 -4
  87. package/src/controller/restore.js +24 -8
  88. package/src/controller/sort.js +59 -3
  89. package/src/controller/sprint.js +31 -7
  90. package/src/controller/status.js +8 -4
  91. package/src/controller/task.js +34 -10
  92. package/src/controller/validate.js +197 -7
  93. package/src/git-user-name.js +9 -0
  94. package/src/git-user.js +55 -0
  95. package/src/main.d.ts +387 -9
  96. package/src/main.js +2757 -113
  97. package/src/parse-index.js +219 -17
  98. package/src/parse-task.js +16 -0
  99. package/src/utility.js +274 -0
  100. package/coverage/tmp/coverage-214292-1787777191526-0.json +0 -1
@@ -78,7 +78,7 @@ Options:
78
78
  The date can be in (almost) any format.
79
79
 
80
80
  {b}kanbn find --assigned "name"{b}
81
- Find tasks assigned to a specific user. Use "^$" to find unassigned tasks.
81
+ Find tasks assigned to a specific user. Use "^$" to find unassigned tasks, and {b}@me{b} for tasks assigned to you.
82
82
 
83
83
  {b}kanbn find --workload N{b}
84
84
  Find tasks with a specific calculated workload.
@@ -88,6 +88,28 @@ Options:
88
88
  Find tasks with a specific progress value (between 0 and 1).
89
89
  If multiple values are specified, find tasks with progress between the lowest and highest inputs.
90
90
 
91
+ {b}kanbn find --overdue{b}
92
+ {b}kanbn find --no-overdue{b}
93
+ Find tasks that are (or are not) overdue. A task is overdue if it has a due date in the past and
94
+ hasn't been completed. A task with no due date is never overdue.
95
+
96
+ {b}kanbn find --is-started{b}
97
+ {b}kanbn find --no-is-started{b}
98
+ Find tasks that do (or don't) have a started date in their metadata.
99
+
100
+ {b}kanbn find --is-completed{b}
101
+ {b}kanbn find --no-is-completed{b}
102
+ Find tasks that do (or don't) have a completed date in their metadata.
103
+
104
+ {b}kanbn find --in-started-column{b}
105
+ {b}kanbn find --no-in-started-column{b}
106
+ Find tasks that are (or aren't) in one of the board's startedColumns. If the board declares no
107
+ startedColumns, no task is in a started column.
108
+
109
+ {b}kanbn find --in-completed-column{b}
110
+ {b}kanbn find --no-in-completed-column{b}
111
+ Find tasks that are (or aren't) in one of the board's completedColumns.
112
+
91
113
  {b}kanbn find --sub-task "search term"{b}
92
114
  {b}kanbn find -s "search term"{b}
93
115
  Find tasks that have sub-tasks matching the search term.
@@ -137,3 +159,19 @@ Examples:
137
159
 
138
160
  {b}kanbn find --count-sub-tasks 1 --count-sub-tasks 99 --progress 0 -q{b}
139
161
  List the ids of tasks that have sub-tasks but no progress yet.
162
+
163
+ {b}kanbn find --overdue --no-in-started-column -q{b}
164
+ List the ids of overdue tasks that nobody has picked up yet.
165
+
166
+ {b}kanbn find --board "board-slug"{b}
167
+ {b}kanbn find -b "board-slug"{b}
168
+ Target a board other than the main one. Falls back to the KANBN_BOARD environment variable and
169
+ then to the defaultBoard option. See {b}kanbn boards{b} for the list of boards.
170
+
171
+ {b}kanbn find --all-boards{b}
172
+ Search every board in the workspace. A task on several boards appears once, annotated with the
173
+ board and column it occupies on each. Without this, the search is scoped to the target board.
174
+ Computed values are evaluated per board, so a task matches {b}--in-started-column{b} if it is in
175
+ a started column on any of them.
176
+ This can't be combined with {b}--sprint{b}: sprint numbers and names are relative to one board's
177
+ list, so there is no sensible answer across several.
@@ -14,6 +14,7 @@ Options:
14
14
  Output raw data instead of rendering a chart. The data will be returned in JSON format.
15
15
 
16
16
  {b}kanbn gantt --assigned "user"{b}
17
+ {b}kanbn gantt --assigned @me{b}
17
18
  {b}kanbn gantt -a "user"{b}
18
19
  Filter for tasks that are assigned to a particular user.
19
20
 
@@ -30,3 +31,8 @@ Options:
30
31
  {b}kanbn gantt --now "date"{b}
31
32
  {b}kanbn gantt -n "date"{b}
32
33
  Mock the current date used for the "now" line and single-date range filtering.
34
+
35
+ {b}kanbn gantt --board "board-slug"{b}
36
+ {b}kanbn gantt -b "board-slug"{b}
37
+ Target a board other than the main one. Falls back to the KANBN_BOARD environment variable and
38
+ then to the defaultBoard option. See {b}kanbn boards{b} for the list of boards.
@@ -7,6 +7,7 @@ Where {b}<command>{b} is one of:
7
7
  {b}version{b} {d}.......{d} Show package version
8
8
  {b}init{b} {d}..........{d} Initialise kanbn board
9
9
  {b}board{b} {d}.........{d} Show the kanbn board
10
+ {b}boards{b} {d}........{d} List the boards in this workspace
10
11
  {b}task{b} {d}..........{d} Show a kanbn task
11
12
  {b}add{b} {d}...........{d} Add a kanbn task
12
13
  {b}edit{b} {d}..........{d} Edit a kanbn task
@@ -25,6 +26,7 @@ Where {b}<command>{b} is one of:
25
26
  {b}restore{b} {d}.......{d} Restore a task from the archive
26
27
  {b}remove-all{b} {d}....{d} Remove the kanbn board and all tasks
27
28
  {b}history{b} {d}.......{d} Show task history
29
+ {b}contributors{b} {d}..{d} List the workspace's contributors
28
30
 
29
31
  For more help with commands, try:
30
32
 
@@ -20,6 +20,7 @@ Options:
20
20
  If two or more dates are provided, show history from the earliest to latest date.
21
21
 
22
22
  {b}kanbn history --assigned "user"{b}
23
+ {b}kanbn history --assigned @me{b}
23
24
  {b}kanbn history -a "user"{b}
24
25
  Filter for tasks assigned to a specific user.
25
26
 
@@ -27,3 +28,8 @@ Options:
27
28
  {b}kanbn history -t "task-id"{b}
28
29
  Filter for one or more task ids.
29
30
  This option can be repeated.
31
+
32
+ {b}kanbn history --board "board-slug"{b}
33
+ {b}kanbn history -b "board-slug"{b}
34
+ Target a board other than the main one. Falls back to the KANBN_BOARD environment variable and
35
+ then to the defaultBoard option. See {b}kanbn boards{b} for the list of boards.
@@ -19,3 +19,16 @@ Options:
19
19
  {b}kanbn init --column "column"{b}
20
20
  {b}kanbn init -c "column"{b}
21
21
  Initialise a kanbn board and add the specified column. This option can be repeated to add multiple columns.
22
+
23
+ {b}kanbn init --board "board-slug"{b}
24
+ {b}kanbn init -b "board-slug"{b}
25
+ Create a secondary board beside the main one, at {b}.kanbn/board-slug.md{b}. Secondary boards
26
+ share the main board's task folder, so a task can appear on several boards, in a different
27
+ column on each. Combine with {b}-n{b}, {b}-d{b} and {b}-c{b} to set the board's name,
28
+ description and columns:
29
+ {b}kanbn init -b design -n "Design Pipeline" -c Ideas -c Designing -c "Signed Off"{b}
30
+ Running it again on an existing board updates its name, description and columns, exactly as
31
+ {b}kanbn init{b} does for the main board. A new board only picks up the default started and
32
+ completed columns if it actually has columns by those names, so a board with its own workflow
33
+ doesn't silently inherit "In Progress" and "Done".
34
+ The workspace has to exist first - run {b}kanbn init{b} with no {b}-b{b} to create it.
@@ -21,3 +21,29 @@ Options:
21
21
  Move the task to a position relative to its current position in the target column.
22
22
  When specifying a negative value for N, the negative sign can be escaped with '/' or '\\' to prevent the value being recognised as an option. For example:
23
23
  {b}kanbn mv "task-1" -p \\-1 --relative{b}
24
+
25
+ {b}kanbn move "task-id" --board "board-slug"{b}
26
+ {b}kanbn move "task-id" -b "board-slug"{b}
27
+ Move the task on a board other than the main one. If the task isn't on that board yet it is
28
+ added, with a notice - so pulling work onto a board is one command rather than two.
29
+
30
+ {b}kanbn move "task-id" -b "board-slug" --no-add{b}
31
+ Refuse to move a task that isn't on the target board, instead of adding it.
32
+ The main board never adds implicitly: moving an untracked task there is an error either way.
33
+
34
+
35
+ Simple tasks - lines in a column that aren't task links - can be moved too, by title:
36
+
37
+ {b}kanbn move "Buy milk" -c "Done"{b}
38
+ Move a simple task to another column. The title matches exactly, ignoring case, or slugified.
39
+ A real task with the same id always wins. Leave off {b}-c{b} to reposition it in its own column.
40
+
41
+ {b}kanbn move "Buy milk" -b "board-slug" -c "column"{b}
42
+ Move a simple task onto another board. A simple task is content in one board file rather than a
43
+ shared task file, so this moves the line: it leaves this board and joins the other one.
44
+
45
+ Boards can declare {b}actions{b} - rules that fire when a task changes, e.g. "when this enters In
46
+ Progress, assign it to me and tag it active". See {b}docs/actions.md{b}.
47
+
48
+ {b}kanbn move --no-actions{b}
49
+ Run without firing any action rules. {b}KANBN_NO_ACTIONS=1{b} does the same for a whole shell.
@@ -1,12 +1,33 @@
1
1
  {b}kanbn remove "task-id"{b}
2
2
  {b}kanbn rm "task-id"{b}
3
3
 
4
- Remove an existing task.
4
+ Remove an existing task. This deletes the task file and its index entry.
5
5
 
6
6
  Options:
7
7
  {b}kanbn remove "task-id" --index{b}
8
+ {b}kanbn remove "task-id" -x{b}
8
9
  Only remove the task from the index. The task file will not be deleted.
9
10
 
10
11
  {b}kanbn remove "task-id" --force{b}
11
12
  {b}kanbn remove "task-id" -f{b}
12
13
  Force remove the task without asking for confirmation.
14
+
15
+ {b}kanbn remove "task-id" --board "board-slug"{b}
16
+ {b}kanbn remove "task-id" -b "board-slug"{b}
17
+ Remove the task from that board. Combine this with {b}--index{b} to remove it from that board
18
+ only - boards own membership, so the task file and its entries on every other board are
19
+ untouched.
20
+
21
+ {b}kanbn remove "task-id" --all-boards{b}
22
+ Task files are shared between boards, so deleting one while another board still references it is
23
+ refused. This removes the task from every board that references it, then deletes the file.
24
+
25
+ {b}kanbn remove "Buy milk"{b}
26
+ Remove a simple task - a line in a column that isn't a task link - by title. There is no file to
27
+ delete and nothing to archive, so {b}--index{b} and {b}--all-boards{b} don't apply.
28
+
29
+ Boards can declare {b}actions{b} - rules that fire when a task changes, e.g. "when this enters In
30
+ Progress, assign it to me and tag it active". See {b}docs/actions.md{b}.
31
+
32
+ {b}kanbn remove --no-actions{b}
33
+ Run without firing any action rules. {b}KANBN_NO_ACTIONS=1{b} does the same for a whole shell.
@@ -11,3 +11,8 @@ Options:
11
11
  {b}kanbn rename "task-id" --name "name"{b}
12
12
  {b}kanbn rename "task-id" -n "name"{b}
13
13
  Rename the task with the specified name. This option is required if not renaming a task interactively.
14
+
15
+ {b}kanbn rename "task-id" --board "board-slug"{b}
16
+ {b}kanbn rename "task-id" -b "board-slug"{b}
17
+ Target a board other than the main one. Falls back to the KANBN_BOARD environment variable and
18
+ then to the defaultBoard option. See {b}kanbn boards{b} for the list of boards.
@@ -10,3 +10,15 @@ Options:
10
10
  {b}kanbn restore "task-id" --column "column"{b}
11
11
  {b}kanbn restore "task-id" -c "column"{b}
12
12
  Restore a task from the archive and place it in the specified column.
13
+
14
+ {b}kanbn restore "task-id" --board "board-slug"{b}
15
+ {b}kanbn restore "task-id" -b "board-slug"{b}
16
+ Restore the task to that board only. Without this, the task goes back to every board it was on
17
+ when it was archived, in the column it occupied on each. A board that has since been deleted is
18
+ reported and skipped rather than failing the restore.
19
+
20
+ Boards can declare {b}actions{b} - rules that fire when a task changes, e.g. "when this enters In
21
+ Progress, assign it to me and tag it active". See {b}docs/actions.md{b}.
22
+
23
+ {b}kanbn restore --no-actions{b}
24
+ Run without firing any action rules. {b}KANBN_NO_ACTIONS=1{b} does the same for a whole shell.
@@ -98,6 +98,21 @@ Options:
98
98
  {b}kanbn sort -w{b}
99
99
  Sort tasks by workload.
100
100
 
101
+ {b}kanbn sort --overdue{b}
102
+ Sort tasks by whether they are overdue. Ascending puts overdue tasks last.
103
+
104
+ {b}kanbn sort --is-started{b}
105
+ Sort tasks by whether they have a started date in their metadata.
106
+
107
+ {b}kanbn sort --is-completed{b}
108
+ Sort tasks by whether they have a completed date in their metadata.
109
+
110
+ {b}kanbn sort --in-started-column{b}
111
+ Sort tasks by whether they are in one of the board's startedColumns.
112
+
113
+ {b}kanbn sort --in-completed-column{b}
114
+ Sort tasks by whether they are in one of the board's completedColumns.
115
+
101
116
  {b}kanbn sort --<custom field name>{b}
102
117
  Sort tasks by a custom field value.
103
118
 
@@ -107,3 +122,11 @@ Examples:
107
122
 
108
123
  {b}kanbn sort "Todo" -z -n --count-tags{b}
109
124
  Sort tasks in the "Todo" column first by name, then by the number of tags, all in descending order
125
+
126
+ {b}kanbn sort "Todo" --overdue -z -e -a{b}
127
+ Sort tasks in the "Todo" column so that overdue tasks come first, then by due date in ascending order
128
+
129
+ {b}kanbn sort "column" --board "board-slug"{b}
130
+ {b}kanbn sort "column" -b "board-slug"{b}
131
+ Target a board other than the main one. Falls back to the KANBN_BOARD environment variable and
132
+ then to the defaultBoard option. See {b}kanbn boards{b} for the list of boards.
@@ -15,3 +15,12 @@ Options:
15
15
  {b}kanbn sprint --description "description"{b}
16
16
  {b}kanbn sprint -d "description"{b}
17
17
  Start a new sprint with the specified description.
18
+
19
+ {b}kanbn sprint --board "board-slug"{b}
20
+ {b}kanbn sprint -b "board-slug"{b}
21
+ Add a sprint from the context of another board. Sprints are workspace-level by default, so this
22
+ appends to the workspace list and says so. A board that declares its own {b}sprints{b} in its
23
+ front matter gets the sprint appended there instead, auto-named {b}{Board name} Sprint {n}{b} so
24
+ that two boards' sprints can't be confused.
25
+ A board with its own list can't see the workspace sprints at all - that's the cost of forking,
26
+ and it's why forking is a deliberate front-matter edit rather than a flag.
@@ -15,7 +15,11 @@ Options:
15
15
 
16
16
  {b}kanbn status --untracked{b}
17
17
  {b}kanbn status -u{b}
18
- Show a list of untracked task filenames.
18
+ Show a list of untracked task filenames. "Untracked" is workspace-scoped: a task is tracked if
19
+ any board references it, so this lists task files that are on no board at all.
20
+ When other boards track tasks that the target board doesn't, they're listed separately under
21
+ {b}tasksOnOtherBoards{b}, with the column each one occupies - the "what could I pull onto this
22
+ board" list.
19
23
 
20
24
  {b}kanbn status --due{b}
21
25
  {b}kanbn status -e{b}
@@ -33,3 +37,8 @@ Options:
33
37
  This option can be repeated - if multiple dates are specified, show task workloads for tasks between the earliest and latest dates.
34
38
  The date can be in (almost) any format.
35
39
  This option will be ignored if the --quiet or --sprint options are set.
40
+
41
+ {b}kanbn status --board "board-slug"{b}
42
+ {b}kanbn status -b "board-slug"{b}
43
+ Target a board other than the main one. Falls back to the KANBN_BOARD environment variable and
44
+ then to the defaultBoard option. See {b}kanbn boards{b} for the list of boards.
@@ -7,3 +7,12 @@ Options:
7
7
  {b}kanbn task "task-id" --json{b}
8
8
  {b}kanbn task "task-id" -j{b}
9
9
  Show task information in JSON format.
10
+
11
+ {b}kanbn task "task-id" --board "board-slug"{b}
12
+ {b}kanbn task "task-id" -b "board-slug"{b}
13
+ Target a board other than the main one. Falls back to the KANBN_BOARD environment variable and
14
+ then to the defaultBoard option. See {b}kanbn boards{b} for the list of boards.
15
+
16
+ {b}kanbn task "Buy milk"{b}
17
+ A simple task - a line in a column that isn't a task link - has no task file to show, so this
18
+ reports which column it's in and how to promote it.
@@ -5,6 +5,11 @@ Validate kanbn index file and all task files, and report any formatting errors.
5
5
  If the files are valid, this also reports tasks whose started/completed dates don't match the column
6
6
  they're in - which usually means the task was moved by hand or by a merge, rather than through kanbn.
7
7
 
8
+ It also lists any line in a column that isn't a task link. Those lines are kept in the board file and
9
+ ignored by every other command, so this is information rather than a problem - except for a line that
10
+ looks like a task link with a typo in it, or one naming a task file that exists, both of which mean a
11
+ task isn't being tracked when it probably should be.
12
+
8
13
  Options:
9
14
  {b}kanbn validate --save{b}
10
15
  Re-save the index and task files. This will ensure that all index column sorting settings are applied and that all tasks are formatted correctly.
@@ -20,4 +25,27 @@ Options:
20
25
 
21
26
  {b}kanbn validate --json{b}
22
27
  {b}kanbn validate -j{b}
23
- Output validation errors in JSON format.
28
+ Output validation errors in JSON format. When there is nothing to report beyond date drift this
29
+ is the bare list of drift entries; when there are warnings as well - or the workspace has more
30
+ than one board - it is an object with {b}drift{b} and {b}warnings{b} keys.
31
+
32
+ {b}kanbn validate --board "board-slug"{b}
33
+ {b}kanbn validate -b "board-slug"{b}
34
+ Target a board other than the main one. Falls back to the KANBN_BOARD environment variable and
35
+ then to the defaultBoard option. See {b}kanbn boards{b} for the list of boards.
36
+
37
+ {b}kanbn validate --all-boards{b}
38
+ Validate every board in the workspace and the tasks each of them references, rather than just
39
+ the target board.
40
+
41
+ In a workspace with more than one board, {b}validate{b} also reports multi-board warnings - a
42
+ workspace-scoped option in a board file, several boards stamping the same shared date, sprints out
43
+ of order, a task on no board at all, history naming a board that has been deleted, and markdown
44
+ files beside the boards that don't parse as one. These are warnings, not errors: each describes a
45
+ workspace that still works, just not the way its author probably meant it to.
46
+
47
+ Action rules are checked too. A rule that names an unknown event or verb, moves to a column that
48
+ doesn't exist, or writes a field Kanbn manages is an {b}error{b} - the same commands that would have
49
+ run it fail before writing anything. Rules that work but probably don't do what they look like -
50
+ two rules writing the same field on the same event, or {b}@me{b} where no user can be resolved - are
51
+ reported as warnings.
@@ -0,0 +1,145 @@
1
+ # Contributors
2
+
3
+ `assigned` and comment `author` are free text, and they always will be. There is no authentication in
4
+ Kanbn and there is never going to be any, so it cannot and should not try to prove that a given string
5
+ corresponds to a given human — anyone who can edit `.kanbn/tasks/*.md` can write any name they like
6
+ into any field.
7
+
8
+ What Kanbn _can_ do is make the common case — "that's me" — a single keystroke instead of a retyped
9
+ name, and make the set of names a workspace uses discoverable rather than folkloric. That is what
10
+ `contributors` is for.
11
+
12
+ **Contributors are a convenience list, not an access control list.** Nothing is validated against
13
+ them, nothing is rejected, and nothing in an existing workspace changes when you add them.
14
+
15
+ ## Declaring contributors
16
+
17
+ `contributors` is a [workspace-scoped option](index-structure.md#project-options): it goes in
18
+ `kanbn.yml` / `kanbn.json`, or in the main board's front matter when there is no configuration file,
19
+ and every board in the workspace inherits it. A secondary board that declares its own is reported by
20
+ `kanbn validate` and ignored — a name written into a shared task file has to mean the same thing on
21
+ every board that references that file.
22
+
23
+ The shorthand is a bare name, which is all most workspaces ever need:
24
+
25
+ ```yaml
26
+ contributors:
27
+ - gordon
28
+ - dave
29
+ - sam
30
+ ```
31
+
32
+ The long form is for a contributor who needs more than a name. Both forms can appear in the same list:
33
+
34
+ ```yaml
35
+ contributors:
36
+ - name: gordon
37
+ displayName: Gordon Larrigan
38
+ email: gordonlarrigan@example.com
39
+ aliases:
40
+ - Gordon Larrigan
41
+ - gordonl
42
+ colour: '#7c5cff'
43
+ - dave
44
+ ```
45
+
46
+ | Field | Required | Purpose |
47
+ | --- | --- | --- |
48
+ | `name` | yes | The canonical value written into `assigned` and comment `author`. Everything else is lookup metadata |
49
+ | `displayName` | no | Shown in UIs; never stored in a task file. Defaults to `name` |
50
+ | `email` | no | Matched against `git config user.email` |
51
+ | `aliases` | no | Other spellings that mean this person |
52
+ | `colour` | no | Presentational only, for avatar chips. Kanbn stores and serves it, and never interprets it |
53
+
54
+ `aliases` is the field that does the actual work. Without it, `contributors` is a list of strings a UI
55
+ can put in a dropdown; with it, Kanbn can tell that the person at this machine is `gordon` even though
56
+ git says `Gordon Larrigan`.
57
+
58
+ ## The current user
59
+
60
+ Kanbn resolves a single answer to "who is the current user?", used by the CLI, the library and the
61
+ VSCode extension. In order, first match wins:
62
+
63
+ 1. the `KANBN_USER` environment variable, used **exactly as given**
64
+ 2. `git config user.email` matched against a contributor's `email` → that contributor's `name`
65
+ 3. `git config user.name` matched against a contributor's `name`, `displayName` or `aliases`,
66
+ ignoring case → that contributor's `name`
67
+ 4. `git config user.name` as-is
68
+ 5. nobody
69
+
70
+ Two things follow from that order:
71
+
72
+ - **It degrades to what Kanbn has always done.** With no contributors declared, steps 2 and 3 can't
73
+ match and step 4 returns exactly the git username Kanbn used before this feature existed. A
74
+ workspace that ignores contributors sees no change at all.
75
+ - **It canonicalises.** With contributors declared, a machine whose git username is `Gordon Larrigan`
76
+ writes `gordon` into the task file, because that is what the workspace has agreed to call him. That
77
+ is the typo mitigation, and it happens without anyone typing anything.
78
+
79
+ `KANBN_USER` is used verbatim rather than canonicalised: it is the explicit override, for a machine
80
+ whose git identity is wrong or missing, and an explicit value should be written exactly as given.
81
+
82
+ Ask Kanbn who it thinks you are with `kanbn contributors`.
83
+
84
+ _There is deliberately no `me` key in the config file. A `me` committed into a shared board file would
85
+ tell every collaborator that they are you. `KANBN_USER` plus git resolution covers the real cases._
86
+
87
+ ## What uses it
88
+
89
+ | Where | Behaviour |
90
+ | --- | --- |
91
+ | `kanbn add --assigned` (no value) | Assigns the task to the current user, canonicalised |
92
+ | `kanbn edit "task-id" --assigned` (no value) | The same |
93
+ | `kanbn comment "task-id"` | The comment author defaults to the current user, or to no author at all if there isn't one |
94
+ | `kanbn add -i` / `kanbn edit -i` | "Assigned to:" becomes an autocomplete over the contributor list when one is declared. Free text is still accepted |
95
+ | `kanbn find --assigned @me` | `@me` expands to the current user. Also `kanbn burndown`, `kanbn gantt` and `kanbn history` |
96
+ | Task history | Each history event records the current user as its `author`, and no `author` key at all when there is no resolvable user |
97
+
98
+ `@me` is only ever interpreted in a **filter** argument, never when setting a value and never inside a
99
+ task file. If the current user can't be resolved, `@me` is an error rather than a filter that quietly
100
+ matches everything.
101
+
102
+ ## Adopting contributors in an existing workspace
103
+
104
+ `kanbn contributors --usage` shows how each contributor is actually used, and — the useful part —
105
+ every name used in a task that isn't a known contributor:
106
+
107
+ ```
108
+ $ kanbn contributors --usage
109
+ 2 contributors:
110
+
111
+ gordon (you)
112
+ 14 tasks, assigned 12, 4 comments
113
+ written as "Gordon Larrigan" in 2 tasks
114
+
115
+ dave
116
+ 6 tasks, assigned 6, 1 comment
117
+
118
+ 1 name is used in tasks but isn't a known contributor:
119
+
120
+ Gordon
121
+ 12 tasks, assigned 12, 0 comments
122
+ task-1, task-4, task-9, ...
123
+ ```
124
+
125
+ That is the list of aliases to add. It is read-only: nothing is rewritten, because renaming `Gordon`
126
+ to `gordon` across every task file is a bulk mutation that deserves its own command and its own dry
127
+ run.
128
+
129
+ `kanbn validate` reports the same thing more briefly, as a **warning** rather than an error — the
130
+ tasks it names are working exactly as they always have. Nothing is reported at all when a workspace
131
+ declares no contributors.
132
+
133
+ ## Deliberate omissions
134
+
135
+ - **Validation.** `assigned` is never restricted to the contributor list. "If contributors is set,
136
+ only allow those values" turns an optional convenience into something that breaks a workspace
137
+ whenever someone adds a task on a machine with a stale config, or renames themselves, or receives a
138
+ task file from outside.
139
+ - **Multiple assignees.** `assigned` is a single string in the schema, the filters, the board template
140
+ and three reporting commands. One assignee per task.
141
+ - **Importing from `package.json`, `.mailmap` or `CODEOWNERS`.** npm contributors are publishers,
142
+ `.mailmap` is git plumbing, and `CODEOWNERS` is a permissions file — three different sets of
143
+ semantics, none of them this one.
144
+ - **Anything resembling accounts.** No permissions, no ownership, no invites. If `contributors` ever
145
+ grows those, it has become an auth system by accident.
@@ -41,7 +41,7 @@ filters:
41
41
  | `due` | `--due`, `-e` | date | `due` metadata |
42
42
  | `plannedStart` | `--plannedStart` | date | `plannedStart` metadata |
43
43
  | `plannedFinish` | `--plannedFinish` | date | `plannedFinish` metadata |
44
- | `assigned` | `--assigned` | string | `assigned` metadata (empty string if unset) |
44
+ | `assigned` | `--assigned` | string | `assigned` metadata (empty string if unset). `@me` on the command line expands to the [current user](contributors.md#the-current-user) |
45
45
  | `workload` | `--workload` | number | The task's [calculated workload](index-structure.md#taskworkloadtags) |
46
46
  | `progress` | `--progress` | number | The task's [calculated progress](task-structure.md#progress) |
47
47
  | `sub-task` | `--sub-task`, `-s` | string | All sub-tasks, one per line, as `[ ] text` or `[x] text` |
@@ -52,6 +52,11 @@ filters:
52
52
  | `count-relations` | `--count-relations` | number | Number of relations |
53
53
  | `comment` | `--comment` | string | All comments, one per line, as `author text` |
54
54
  | `count-comments` | `--count-comments` | number | Number of comments |
55
+ | `overdue` | `--overdue` | boolean | Whether the task is [overdue](#computed-values) |
56
+ | `is-started` | `--is-started` | boolean | Whether the task has a started date |
57
+ | `is-completed` | `--is-completed` | boolean | Whether the task has a completed date |
58
+ | `in-started-column` | `--in-started-column` | boolean | Whether the task is in one of the board's `startedColumns` |
59
+ | `in-completed-column` | `--in-completed-column` | boolean | Whether the task is in one of the board's `completedColumns` |
55
60
  | *custom field name* | `--<custom field name>` | declared type | The custom field value in the task metadata |
56
61
 
57
62
  Custom fields must be declared in the [`customFields`](index-structure.md#customfields) project option before they can be filtered on.
@@ -60,6 +65,8 @@ A task that doesn't have the metadata field being filtered on never matches a da
60
65
 
61
66
  *Note: `hiddenColumns` only affects the board. `kanbn find` still returns tasks in hidden columns unless you filter them out with `column`.*
62
67
 
68
+ `@me` is substituted where the argument is parsed, so it works for `kanbn find --assigned @me` and for the simpler `--assigned` options on `kanbn burndown`, `kanbn gantt` and `kanbn history`. It is never interpreted when *setting* a value, and never inside a task file. If Kanbn can't work out who you are, `@me` is an error rather than a filter that quietly matches everything.
69
+
63
70
  ### String filters
64
71
 
65
72
  String filter values are **case-insensitive regular expressions**, matched anywhere in the value (not anchored). Passing an array (or repeating a CLI option) joins the values with `|`, so an array means "match any of these":
@@ -119,13 +126,53 @@ kanbn find --workload 3 --workload 8 # between 3 and 8
119
126
 
120
127
  ### Boolean filters
121
128
 
122
- Boolean filters only apply to custom fields with type `boolean`, and are matched by exact equality. On the command line, `--<name>` matches `true` and `--no-<name>` matches `false`:
129
+ Boolean filters apply to the [computed values](#computed-values) and to custom fields with type `boolean`, and are matched by exact equality. On the command line, `--<name>` matches `true` and `--no-<name>` matches `false`:
123
130
 
124
131
  ```bash
125
132
  kanbn find --needsDesign # tasks where needsDesign is true
126
133
  kanbn find --no-needsDesign # tasks where needsDesign is false
134
+ kanbn find --overdue # overdue tasks
135
+ kanbn find --no-overdue # tasks that aren't overdue
127
136
  ```
128
137
 
138
+ Leaving the option off entirely is different from passing `--no-<name>`: it means "don't filter on this at all".
139
+
140
+ ## Computed values
141
+
142
+ Most filter and sorter fields read a value straight off the task. These five are worked out from the task *and* the board it is being filtered on, which makes them useful for questions the raw metadata can't answer on its own — "what is overdue and nobody has picked up", "what is sitting in a done column without a completed date".
143
+
144
+ | Value | Meaning |
145
+ | --- | --- |
146
+ | `overdue` | The task has a `due` date that has passed **and** hasn't been completed. A task with no due date is never overdue, and neither is a completed task, however late it was. |
147
+ | `is-started` | The task has a started date in its metadata. |
148
+ | `is-completed` | The task has a completed date in its metadata. |
149
+ | `in-started-column` | The task is currently in one of the board's [`startedColumns`](index-structure.md#startedcolumns). |
150
+ | `in-completed-column` | The task is currently in one of the board's [`completedColumns`](index-structure.md#completedcolumns). |
151
+
152
+ `is-started` and `is-completed` read the metadata fields the board is configured to use, so a board with a [`startedField`](index-structure.md#startedfield) or [`completedField`](index-structure.md#completedfield) override reports its own state rather than the built-in `started` / `completed` fields. A board that declares no `startedColumns` has no notion of work in progress, so nothing is in a started column; the same goes for `completedColumns`.
153
+
154
+ `is-completed` and `in-completed-column` normally agree, because moving a task into a completed column is what stamps the completed date (likewise `is-started` and `in-started-column`). They come apart when a task is edited directly, when a board overrides the state fields, or when a task is moved back out of a column - which is exactly when it's worth asking about them separately:
155
+
156
+ ```bash
157
+ # Tasks sitting in a completed column with no completed date
158
+ kanbn find --in-completed-column --no-is-completed
159
+
160
+ # Overdue work that nobody has picked up
161
+ kanbn find --overdue --no-in-started-column
162
+ ```
163
+
164
+ Under `kanbn find --all-boards` every board is filtered on its own, so a task matches `--in-started-column` if it is in a started column on **any** board in the workspace. Scope the question to one board with `--board`.
165
+
166
+ As with the other fields, the name written in YAML is not always the command line option, and the sorter form is camelCase where the filter form is kebab-case:
167
+
168
+ | Computed value | Filter field | Sorter field | CLI option |
169
+ | --- | --- | --- | --- |
170
+ | Overdue | `overdue` | `overdue` | `--overdue` |
171
+ | Started | `is-started` | `isStarted` | `--is-started` |
172
+ | Completed | `is-completed` | `isCompleted` | `--is-completed` |
173
+ | In a started column | `in-started-column` | `inStartedColumn` | `--in-started-column` |
174
+ | In a completed column | `in-completed-column` | `inCompletedColumn` | `--in-completed-column` |
175
+
129
176
  ## Sorters
130
177
 
131
178
  A sorter list is an ordered array. Tasks are compared using the first sorter; ties are broken using the next one, and so on. Each sorter is an object:
@@ -145,7 +192,12 @@ sorters:
145
192
  | `order` | no | `ascending` (default) or `descending` |
146
193
  | `filter` | no | A regex used to transform values before comparing them (see below) |
147
194
 
148
- Strings are compared with `localeCompare` (accent-sensitive, case-insensitive); dates and numbers are compared numerically.
195
+ Strings are compared with `localeCompare` (accent-sensitive, case-insensitive); dates and numbers are compared numerically. Booleans sort `false` before `true`, so `order: descending` on a [computed value](#computed-values) brings the matching tasks to the top:
196
+
197
+ ```bash
198
+ # Overdue tasks first, then everything else by due date
199
+ kanbn sort "Todo" --overdue -z --due -a
200
+ ```
149
201
 
150
202
  ### Sort filters
151
203
 
@@ -188,6 +240,11 @@ kanbn sort "Todo" --name "Task (\d+)"
188
240
  | `countRelations` | `--count-relations` |
189
241
  | `comments` | `--comment` |
190
242
  | `countComments` | `--count-comments` |
243
+ | `overdue` | `--overdue` |
244
+ | `isStarted` | `--is-started` |
245
+ | `isCompleted` | `--is-completed` |
246
+ | `inStartedColumn` | `--in-started-column` |
247
+ | `inCompletedColumn` | `--in-completed-column` |
191
248
  | *custom field name* | `--<custom field name>` |
192
249
 
193
250
  [View](views.md) column `sorters` accept all of the same fields, plus `column` (the index column the task is currently in), which is useful in a view whose columns don't map onto index columns.