@zinn-dev/cli 0.3.0 → 0.6.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/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright 2026 Zinn
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -13,23 +13,28 @@ Set `ZINN_DIR` to use another Zinn directory and keep using the same value for c
13
13
 
14
14
  ## Start a project
15
15
 
16
- Create a project with a name and a short key that begins with a letter and then uses only letters and numbers:
16
+ Create a project with a key or optionally provide a name:
17
17
 
18
18
  ```sh
19
- zinn project create "Website refresh" SITE
19
+ zinn project create MDR --name "Macrodata Refinement"
20
20
  ```
21
21
 
22
- Project keys are stored in uppercase. Each project starts with _Backlog_, _TODO_, _In Progress_, _Review_, and _Done_ columns. List projects or inspect a project's columns with:
22
+ Project keys are stored in **uppercase**. You can create a project without a project name, like `zinn project create MDR`, which will just default to having the key as the project name too.
23
+ Intetionally empty or whitespace project names are rejected.
24
+
25
+ Each project starts with _Backlog_, _TODO_, _In Progress_, _Review_, and _Done_ columns.
26
+
27
+ You can list projects or inspect a project's columns with:
23
28
 
24
29
  ```sh
25
30
  zinn project list
26
- zinn project column list SITE
31
+ zinn project column list MDR
27
32
  ```
28
33
 
29
34
  Rename a project:
30
35
 
31
36
  ```sh
32
- zinn project edit SITE --name "Website redesign"
37
+ zinn project edit MDR --name "Macrodata Refinement (Morning Shift)"
33
38
  ```
34
39
 
35
40
  The `--name` flag is required. Names must contain printable text on a single line.
@@ -39,26 +44,26 @@ Use `--name="--example"` when a value begins with a dash.
39
44
  Add another column at the end of the board:
40
45
 
41
46
  ```sh
42
- zinn project column create SITE "Waiting"
47
+ zinn project column create MDR "Boardlog"
43
48
  ```
44
49
 
45
- `zinn project delete SITE` permanently deletes the project and all of its columns and tasks. The command does not ask for confirmation.
50
+ `zinn project delete MDR` asks for confirmation, then permanently deletes the project and all of its columns and tasks.
46
51
 
47
52
  ## Create and read tasks
48
53
 
49
54
  Create a task with a title and an optional description. New tasks enter the project's first column:
50
55
 
51
56
  ```sh
52
- zinn task create SITE "Rewrite the home page"
53
- zinn task create SITE "Check the mobile layout" "Test the navigation at narrow widths"
57
+ zinn task create MDR "Refine 75% of the numbers"
58
+ zinn task create MDR "Review the employee handbook" "Prepare for a 75% Dance Experience"
54
59
  ```
55
60
 
56
- Tasks are created with keys such as `SITE-1`. List active tasks, optionally limited to one project, or view one task:
61
+ Tasks are created with keys such as `MDR-1`. List active tasks, optionally limited to one project, or view one task:
57
62
 
58
63
  ```sh
59
64
  zinn task list
60
- zinn task list SITE
61
- zinn task view SITE-1
65
+ zinn task list MDR
66
+ zinn task view MDR-1
62
67
  ```
63
68
 
64
69
  When a project key is supplied, the list follows the project's column order and the task order within each column.
@@ -68,12 +73,12 @@ When a project key is supplied, the list follows the project's column order and
68
73
  Edit a task's title, description, or both:
69
74
 
70
75
  ```sh
71
- zinn task edit SITE-1 --title "Rewrite the landing page"
72
- zinn task edit SITE-1 --description "Include the new product screenshots"
73
- zinn task edit SITE-1 --title "Rewrite the landing page" --description ""
76
+ zinn task edit MDR-1 --title "Meet the quarterly refinement quota"
77
+ zinn task edit MDR-1 --description "Complete refinement before the waffle party"
78
+ zinn task edit MDR-1 --title "Meet the quarterly refinement quota" --description ""
74
79
  ```
75
80
 
76
- Omitted fields stay unchanged. An empty description is stored as an empty string.
81
+ Only the explicitly specified fields are modified and the rest are untouched. An empty string can be given for the description and is considered valid.
77
82
 
78
83
  At least one flag is required and task titles cannot be blank. Archived tasks can be edited without unarchiving them. Supplying unchanged values does not change the modification timestamp.
79
84
  Use `--title="--example"` when a value begins with a dash.
@@ -83,7 +88,7 @@ Use `--title="--example"` when a value begins with a dash.
83
88
  Move a task to another column in its project:
84
89
 
85
90
  ```sh
86
- zinn task move SITE-1 "In Progress"
91
+ zinn task move MDR-1 "In Progress"
87
92
  ```
88
93
 
89
94
  A moved task appears at the bottom of its destination column. Moving it to its current column does nothing. Archived tasks must be unarchived before they can be moved.
@@ -91,13 +96,13 @@ A moved task appears at the bottom of its destination column. Moving it to its c
91
96
  Change a task's position within its current column:
92
97
 
93
98
  ```sh
94
- zinn task order SITE-2 top
95
- zinn task order SITE-2 up
96
- zinn task order SITE-2 down
97
- zinn task order SITE-2 bottom
98
- zinn task move SITE-2 "In Progress"
99
- zinn task order SITE-2 before SITE-1
100
- zinn task order SITE-2 after SITE-1
99
+ zinn task order MDR-2 top
100
+ zinn task order MDR-2 up
101
+ zinn task order MDR-2 down
102
+ zinn task order MDR-2 bottom
103
+ zinn task move MDR-2 "In Progress"
104
+ zinn task order MDR-2 before MDR-1
105
+ zinn task order MDR-2 after MDR-1
101
106
  ```
102
107
 
103
108
  The task being reordered and the target of `before` or `after` must be active tasks in the same column.
@@ -107,9 +112,9 @@ The task being reordered and the target of `before` or `after` must be active ta
107
112
  Active tasks are shown by default. Archive a task to hide it from active lists, then list archived tasks or all tasks:
108
113
 
109
114
  ```sh
110
- zinn task archive SITE-1
111
- zinn task list SITE --archived
112
- zinn task list SITE --all
115
+ zinn task archive MDR-1
116
+ zinn task list MDR --archived
117
+ zinn task list MDR --all
113
118
  ```
114
119
 
115
120
  `--archived` and `--all` cannot be used together. In an `--all` listing, Zinn adds an Active or Archived status column.
@@ -117,10 +122,10 @@ zinn task list SITE --all
117
122
  Unarchiving puts a task at the bottom of its previous column:
118
123
 
119
124
  ```sh
120
- zinn task unarchive SITE-1
125
+ zinn task unarchive MDR-1
121
126
  ```
122
127
 
123
- Delete a task permanently with `zinn task delete SITE-1`. Unlike project deletion, task deletion asks for confirmation.
128
+ Delete a task permanently with `zinn task delete MDR-1`. It asks for confirmation before performing the action.
124
129
 
125
130
  ## Help
126
131
 
@@ -136,4 +141,4 @@ zinn task move --help
136
141
 
137
142
  The short `-h` form works in the same positions.
138
143
 
139
- Running `zinn` without a command launches the work-in-progress TUI when attached to an interactive terminal. The commands documented above provide the complete current workflow.
144
+ Running `zinn` without a command shows help
package/index.ts CHANGED
@@ -1,21 +1,9 @@
1
1
  #!/usr/bin/env bun
2
- import { quit } from "./src/lib";
3
2
 
4
3
  const args = process.argv.slice(2);
5
4
 
6
- if (args.length === 0) {
7
- if (!!process.stdout.isTTY) {
8
- const tui = await import("@zinn-dev/tui");
9
- tui.launch();
10
- } else {
11
- quit("Direct launch in a non-TTY environment is not supported.");
12
- }
13
- } else {
14
- // TODO: isTTY check for human readable colored and structured formatting like tables
15
- const firstArg = args[0]!;
16
- // TODO: root routing with flags
17
- if (["-h", "--help"].includes(firstArg)) {
18
- console.info(`ZINN - A kanban workflow in the terminal
5
+ if (args.length === 0 || ["-h", "--help"].includes(args[0]!)) {
6
+ console.info(`ZINN - A kanban workflow in the terminal
19
7
 
20
8
  Usage: zinn <command>
21
9
 
@@ -39,11 +27,10 @@ Commands:
39
27
  task delete
40
28
 
41
29
  Run zinn <namespace> --help or zinn <command> --help for more information.
42
- Running zinn without a command opens the work-in-progress TUI in an interactive terminal.`);
43
- } else {
44
- const { createRouter } = await import("./src/routes/router");
45
- const { routes } = await import("./src/routes/routes");
46
- const router = createRouter(routes);
47
- router.route(args);
48
- }
30
+ Running zinn without a command shows this help.`);
31
+ } else {
32
+ const { createRouter } = await import("./src/routes/router");
33
+ const { routes } = await import("./src/routes/routes");
34
+ const router = createRouter(routes);
35
+ router.route(args);
49
36
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zinn-dev/cli",
3
- "version": "0.3.0",
3
+ "version": "0.6.0",
4
4
  "description": "A kanban workflow in the terminal.",
5
5
  "license": "MIT",
6
6
  "bugs": {
@@ -13,14 +13,13 @@
13
13
  },
14
14
  "repository": {
15
15
  "type": "git",
16
- "url": "git+https://github.com/yethranayeh/zinn.git"
16
+ "url": "git+https://github.com/yethranayeh/zinn.git",
17
+ "directory": "packages/cli"
17
18
  },
18
19
  "keywords": [
19
20
  "kanban",
20
21
  "cli",
21
22
  "terminal",
22
- "tui",
23
- "opentui",
24
23
  "bun"
25
24
  ],
26
25
  "module": "index.ts",
@@ -32,7 +31,8 @@
32
31
  },
33
32
  "files": [
34
33
  "index.ts",
35
- "src"
34
+ "src",
35
+ "LICENSE"
36
36
  ],
37
37
  "type": "module",
38
38
  "bin": {
@@ -42,7 +42,6 @@
42
42
  "access": "public"
43
43
  },
44
44
  "dependencies": {
45
- "@zinn-dev/core": "0.3.0",
46
- "@zinn-dev/tui": "0.0.1"
45
+ "@zinn-dev/core": "0.5.0"
47
46
  }
48
47
  }
@@ -58,27 +58,53 @@ Example: zinn project edit MDR --name "Macrodata Refinement"`,
58
58
 
59
59
  create: {
60
60
  run: (args: Array<string>) => {
61
- const projectName = args[0];
62
- // TODO: maybe auto generate project key from name instead of forcing explicit input (however, very open to collision)
63
- const projectKey = args[1];
61
+ const { values, positionals, tokens } = parseArgs({
62
+ args,
63
+ options: { name: { type: "string" } },
64
+ allowPositionals: true,
65
+ strict: true,
66
+ tokens: true,
67
+ });
68
+
69
+ const projectKey = positionals[0];
70
+
71
+ if (projectKey == null) {
72
+ quit("Project key must be specified");
73
+ }
74
+
75
+ if (positionals.length > 1) {
76
+ quit("Only one project key can be specified");
77
+ }
64
78
 
65
- if (projectName == null || projectKey == null) {
66
- quit("Both the project name and the project key must be defined");
79
+ const parsedArgs = new Set<string>();
80
+ for (const token of tokens) {
81
+ if (token.kind !== "option") {
82
+ continue;
83
+ }
84
+
85
+ if (parsedArgs.has(token.name)) {
86
+ quit(`The "--${token.name}" flag can only be specified once`);
87
+ }
88
+
89
+ parsedArgs.add(token.name);
67
90
  }
68
91
 
69
92
  try {
70
- const createdProject = project.create({ key: projectKey, name: projectName });
93
+ const createdProject = project.create({ key: projectKey, name: values.name });
71
94
  console.info(`${createdProject.key} | ${createdProject.name}`);
72
95
  } catch (err: any) {
73
96
  quit(err?.message ?? "Something went wrong");
74
97
  }
75
98
  },
76
- help: `Usage: zinn project create <name> <project-key>
99
+ help: `Usage: zinn project create <project-key> [--name <text>]
77
100
 
78
- Create a project with the default Backlog, TODO, In Progress, Review, and Done columns.
101
+ Create a project with the default columns.
79
102
  Project keys are stored in uppercase.
80
103
 
81
- Example: zinn project create "Website refresh" SITE`,
104
+ An omitted name defaults to the uppercase project key.
105
+ Names cannot be blank.
106
+
107
+ Example: zinn project create MDR --name "Macrodata Refinement"`,
82
108
  },
83
109
  list: {
84
110
  run: () => {
@@ -109,18 +135,31 @@ Example: zinn project list`,
109
135
  }
110
136
 
111
137
  try {
112
- // TODO: add y/n confirmation
113
- const deletedProject = project.delete(projectKey);
114
- console.info(`Deleted ${deletedProject.key} | ${deletedProject.name}`);
138
+ const projectMatch = project.getByKey(projectKey);
139
+
140
+ if (projectMatch == null) {
141
+ throw new Error(`Project with key "${projectKey}" does not exist!`);
142
+ }
143
+
144
+ const canDelete = confirm(
145
+ `Are you sure you want to delete ${projectMatch.key} and all of its columns and tasks?`,
146
+ );
147
+
148
+ if (canDelete) {
149
+ const deletedProject = project.delete(projectKey);
150
+ console.info(`Deleted ${deletedProject.key} | ${deletedProject.name}`);
151
+ } else {
152
+ console.info(`Deletion cancelled for ${projectMatch.key} | ${projectMatch.name}`);
153
+ }
115
154
  } catch (err: any) {
116
155
  quit(err?.message ?? "Something went wrong");
117
156
  }
118
157
  },
119
158
  help: `Usage: zinn project delete <project-key>
120
159
 
121
- Permanently delete a project and all of its columns and tasks without confirmation.
160
+ Permanently delete a project and all of its columns and tasks after confirmation.
122
161
 
123
- Example: zinn project delete SITE`,
162
+ Example: zinn project delete MDR`,
124
163
  },
125
164
  column: {
126
165
  create: {
@@ -145,7 +184,7 @@ Example: zinn project delete SITE`,
145
184
 
146
185
  Add a column at the end of a project's board.
147
186
 
148
- Example: zinn project column create SITE "Waiting for review"`,
187
+ Example: zinn project column create MDR "Boardlog"`,
149
188
  },
150
189
  list: {
151
190
  run: (args: Array<string>) => {
@@ -162,7 +201,7 @@ Example: zinn project column create SITE "Waiting for review"`,
162
201
 
163
202
  List a project's columns in board order.
164
203
 
165
- Example: zinn project column list SITE`,
204
+ Example: zinn project column list MDR`,
166
205
  },
167
206
  },
168
207
  } satisfies RouteDef;
@@ -70,7 +70,7 @@ Titles cannot be blank.
70
70
  Archived tasks can be edited. Unchanged values leave the task unchanged.
71
71
  Use --title="--example" for text beginning with a dash.
72
72
 
73
- Example: zinn task edit SITE-1 --title "Rewrite the landing page"`,
73
+ Example: zinn task edit MDR-1 --title "Meet the quarterly refinement quota"`,
74
74
  },
75
75
  create: {
76
76
  run: (args: Array<string>) => {
@@ -111,7 +111,7 @@ Example: zinn task edit SITE-1 --title "Rewrite the landing page"`,
111
111
 
112
112
  Create a task in the project's first column.
113
113
 
114
- Example: zinn task create SITE "Rewrite the home page" "Update the product copy"`,
114
+ Example: zinn task create MDR "Refine the numbers" "Sort the numbers and meet the quarterly quota"`,
115
115
  },
116
116
  list: {
117
117
  run: (args) => {
@@ -177,7 +177,7 @@ Example: zinn task create SITE "Rewrite the home page" "Update the product copy"
177
177
  List active tasks by default.
178
178
  Use --archived to list archived tasks or --all to list both.
179
179
 
180
- Example: zinn task list SITE --all`,
180
+ Example: zinn task list MDR --all`,
181
181
  },
182
182
  view: {
183
183
  run: (args) => {
@@ -194,7 +194,7 @@ Example: zinn task list SITE --all`,
194
194
 
195
195
  Show a task with its current column and description.
196
196
 
197
- Example: zinn task view SITE-1`,
197
+ Example: zinn task view MDR-1`,
198
198
  },
199
199
  move: {
200
200
  run: (args) => {
@@ -220,7 +220,7 @@ matching placement at the bottom of a visual kanban column.
220
220
  Giving a task's current column as the target will not do anything.
221
221
  Archived tasks must be unarchived before they can be moved.
222
222
 
223
- Example: zinn task move SITE-1 "In Progress"`,
223
+ Example: zinn task move MDR-1 "In Progress"`,
224
224
  },
225
225
  order: {
226
226
  run: (args) => {
@@ -272,7 +272,7 @@ Change a task's position within its current column.
272
272
  Use top or bottom for either end, up or down for one position,
273
273
  or before or after to place it relative to another task.
274
274
 
275
- Example: zinn task order SITE-2 before SITE-1`,
275
+ Example: zinn task order MDR-2 before MDR-1`,
276
276
  },
277
277
  delete: {
278
278
  run: (args: Array<string>) => {
@@ -300,7 +300,7 @@ Example: zinn task order SITE-2 before SITE-1`,
300
300
 
301
301
  Permanently delete a task after confirmation.
302
302
 
303
- Example: zinn task delete SITE-1`,
303
+ Example: zinn task delete MDR-1`,
304
304
  },
305
305
  archive: {
306
306
  run: (args: Array<string>) => {
@@ -317,7 +317,7 @@ Example: zinn task delete SITE-1`,
317
317
 
318
318
  Archive a task so it no longer appears in active task lists.
319
319
 
320
- Example: zinn task archive SITE-1`,
320
+ Example: zinn task archive MDR-1`,
321
321
  },
322
322
  unarchive: {
323
323
  run: (args: Array<string>) => {
@@ -334,6 +334,6 @@ Example: zinn task archive SITE-1`,
334
334
 
335
335
  Unarchive a task at the bottom of its previous column.
336
336
 
337
- Example: zinn task unarchive SITE-1`,
337
+ Example: zinn task unarchive MDR-1`,
338
338
  },
339
339
  } satisfies RouteDef;