taskin 0.1.0-beta.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 +21 -0
- package/README.md +119 -0
- package/dist/commands/commands.types.d.ts +13 -0
- package/dist/commands/commands.types.js +6 -0
- package/dist/commands/commands.types.js.map +1 -0
- package/dist/commands/define-command/define-command.d.ts +6 -0
- package/dist/commands/define-command/define-command.js +27 -0
- package/dist/commands/define-command/define-command.js.map +1 -0
- package/dist/commands/define-command/define-command.test.d.ts +4 -0
- package/dist/commands/define-command/define-command.test.js +125 -0
- package/dist/commands/define-command/define-command.test.js.map +1 -0
- package/dist/commands/define-command/define-command.types.d.ts +49 -0
- package/dist/commands/define-command/define-command.types.js +5 -0
- package/dist/commands/define-command/define-command.types.js.map +1 -0
- package/dist/commands/define-command/index.d.ts +5 -0
- package/dist/commands/define-command/index.js +6 -0
- package/dist/commands/define-command/index.js.map +1 -0
- package/dist/commands/finish.d.ts +4 -0
- package/dist/commands/finish.js +69 -0
- package/dist/commands/finish.js.map +1 -0
- package/dist/commands/index.d.ts +9 -0
- package/dist/commands/index.js +10 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +4 -0
- package/dist/commands/init.js +192 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/lint.d.ts +4 -0
- package/dist/commands/lint.js +31 -0
- package/dist/commands/lint.js.map +1 -0
- package/dist/commands/list.d.ts +4 -0
- package/dist/commands/list.js +132 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/pause.d.ts +4 -0
- package/dist/commands/pause.js +69 -0
- package/dist/commands/pause.js.map +1 -0
- package/dist/commands/start.d.ts +4 -0
- package/dist/commands/start.js +70 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/colors.d.ts +26 -0
- package/dist/lib/colors.js +42 -0
- package/dist/lib/colors.js.map +1 -0
- package/dist/lib/file-system-task-linter/file-system-task-linter.d.ts +36 -0
- package/dist/lib/file-system-task-linter/file-system-task-linter.js +219 -0
- package/dist/lib/file-system-task-linter/file-system-task-linter.js.map +1 -0
- package/dist/lib/file-system-task-linter/file-system-task-linter.mock.d.ts +81 -0
- package/dist/lib/file-system-task-linter/file-system-task-linter.mock.js +152 -0
- package/dist/lib/file-system-task-linter/file-system-task-linter.mock.js.map +1 -0
- package/dist/lib/file-system-task-linter/file-system-task-linter.test.d.ts +4 -0
- package/dist/lib/file-system-task-linter/file-system-task-linter.test.js +146 -0
- package/dist/lib/file-system-task-linter/file-system-task-linter.test.js.map +1 -0
- package/dist/lib/file-system-task-linter/file-system-task-linter.types.d.ts +52 -0
- package/dist/lib/file-system-task-linter/file-system-task-linter.types.js +6 -0
- package/dist/lib/file-system-task-linter/file-system-task-linter.types.js.map +1 -0
- package/dist/lib/file-system-task-linter/index.d.ts +6 -0
- package/dist/lib/file-system-task-linter/index.js +7 -0
- package/dist/lib/file-system-task-linter/index.js.map +1 -0
- package/dist/lib/help.d.ts +4 -0
- package/dist/lib/help.js +104 -0
- package/dist/lib/help.js.map +1 -0
- package/dist/lib/index.d.ts +6 -0
- package/dist/lib/index.js +7 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/provider-installer/index.d.ts +5 -0
- package/dist/lib/provider-installer/index.js +6 -0
- package/dist/lib/provider-installer/index.js.map +1 -0
- package/dist/lib/provider-installer/provider-installer.d.ts +28 -0
- package/dist/lib/provider-installer/provider-installer.js +86 -0
- package/dist/lib/provider-installer/provider-installer.js.map +1 -0
- package/dist/lib/provider-installer/provider-installer.types.d.ts +4 -0
- package/dist/lib/provider-installer/provider-installer.types.js +5 -0
- package/dist/lib/provider-installer/provider-installer.types.js.map +1 -0
- package/dist/lib/provider-installer.d.ts +27 -0
- package/dist/lib/provider-installer.js +86 -0
- package/dist/lib/provider-installer.js.map +1 -0
- package/dist/lib/provider-registry/index.d.ts +5 -0
- package/dist/lib/provider-registry/index.js +6 -0
- package/dist/lib/provider-registry/index.js.map +1 -0
- package/dist/lib/provider-registry/provider-registry.d.ts +9 -0
- package/dist/lib/provider-registry/provider-registry.js +111 -0
- package/dist/lib/provider-registry/provider-registry.js.map +1 -0
- package/dist/lib/provider-registry/provider-registry.types.d.ts +5 -0
- package/dist/lib/provider-registry/provider-registry.types.js +6 -0
- package/dist/lib/provider-registry/provider-registry.types.js.map +1 -0
- package/dist/lib/provider-registry.d.ts +26 -0
- package/dist/lib/provider-registry.js +111 -0
- package/dist/lib/provider-registry.js.map +1 -0
- package/dist/lib/task-linter/index.d.ts +5 -0
- package/dist/lib/task-linter/index.js +6 -0
- package/dist/lib/task-linter/index.js.map +1 -0
- package/dist/lib/task-linter/task-linter.d.ts +36 -0
- package/dist/lib/task-linter/task-linter.js +219 -0
- package/dist/lib/task-linter/task-linter.js.map +1 -0
- package/dist/lib/task-linter/task-linter.types.d.ts +52 -0
- package/dist/lib/task-linter/task-linter.types.js +6 -0
- package/dist/lib/task-linter/task-linter.types.js.map +1 -0
- package/dist/lib/task-linter.d.ts +29 -0
- package/dist/lib/task-linter.js +215 -0
- package/dist/lib/task-linter.js.map +1 -0
- package/dist/lib/task-linter.types.d.ts +38 -0
- package/dist/lib/task-linter.types.js +5 -0
- package/dist/lib/task-linter.types.js.map +1 -0
- package/dist/main.d.ts +14 -0
- package/dist/main.js +29 -0
- package/dist/main.js.map +1 -0
- package/dist/taskin.d.ts +33 -0
- package/dist/taskin.js +101 -0
- package/dist/taskin.js.map +1 -0
- package/package.json +81 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 OpenTask (https://opentask.com.br)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Taskin
|
|
2
|
+
|
|
3
|
+
> Task management system integrated with Git workflows
|
|
4
|
+
|
|
5
|
+
Taskin is a command-line tool that helps you manage tasks directly from your terminal, with seamless Git integration and **dynamic provider loading**.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/taskin)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
|
|
10
|
+
## ✨ Features
|
|
11
|
+
|
|
12
|
+
- 🎯 **Multiple Task Providers** - File System, Redmine, Jira, GitHub Issues (and more!)
|
|
13
|
+
- 🔌 **Dynamic Provider Installation** - Automatically installs providers when needed
|
|
14
|
+
- 📦 **Lightweight CLI** - Only installs what you use
|
|
15
|
+
- 🔒 **Secure Configuration** - API keys protected in `.gitignore`
|
|
16
|
+
- 🎨 **Beautiful CLI** - Colorful, interactive, and user-friendly
|
|
17
|
+
- ⚡ **Fast & Efficient** - Built with performance in mind
|
|
18
|
+
- 🧪 **Well Tested** - Comprehensive test coverage
|
|
19
|
+
|
|
20
|
+
## 🚀 Installation
|
|
21
|
+
|
|
22
|
+
\`\`\`bash
|
|
23
|
+
# Using npx (recommended - no installation needed!)
|
|
24
|
+
npx taskin init
|
|
25
|
+
|
|
26
|
+
# Or install globally
|
|
27
|
+
npm install -g taskin
|
|
28
|
+
|
|
29
|
+
# Or with pnpm
|
|
30
|
+
pnpm add -g taskin
|
|
31
|
+
|
|
32
|
+
# Or with yarn
|
|
33
|
+
yarn global add taskin
|
|
34
|
+
\`\`\`
|
|
35
|
+
|
|
36
|
+
> **Note:** This is a beta version. Please report any issues on [GitHub](https://github.com/opentask-app/taskin/issues).
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
1. **Initialize Taskin in your project:**
|
|
41
|
+
\`\`\`bash
|
|
42
|
+
npx taskin init
|
|
43
|
+
\`\`\`
|
|
44
|
+
|
|
45
|
+
Select your preferred task provider:
|
|
46
|
+
- 📁 **File System** - Store tasks as Markdown files locally
|
|
47
|
+
- 🔴 **Redmine** - Sync with Redmine issues (coming soon)
|
|
48
|
+
- 🔵 **Jira** - Sync with Jira issues (coming soon)
|
|
49
|
+
- 🐙 **GitHub Issues** - Sync with GitHub (coming soon)
|
|
50
|
+
|
|
51
|
+
2. **List all tasks:**
|
|
52
|
+
\`\`\`bash
|
|
53
|
+
taskin list
|
|
54
|
+
\`\`\`
|
|
55
|
+
|
|
56
|
+
3. **Start working on a task:**
|
|
57
|
+
\`\`\`bash
|
|
58
|
+
taskin start task-001
|
|
59
|
+
\`\`\`
|
|
60
|
+
|
|
61
|
+
## Commands
|
|
62
|
+
|
|
63
|
+
- \`taskin init\` - Initialize Taskin in your project with interactive setup
|
|
64
|
+
- \`taskin list\` - List all tasks
|
|
65
|
+
- \`taskin start <id>\` - Start working on a task
|
|
66
|
+
- \`taskin pause <id>\` - Pause work on a task
|
|
67
|
+
- \`taskin finish <id>\` - Complete a task
|
|
68
|
+
- \`taskin lint\` - Validate task files
|
|
69
|
+
|
|
70
|
+
## 🏗️ Architecture
|
|
71
|
+
|
|
72
|
+
Taskin uses a **plugin-based architecture** with dynamic provider loading:
|
|
73
|
+
|
|
74
|
+
- Providers are loaded on-demand (only when selected)
|
|
75
|
+
- Automatic installation via npm/pnpm/yarn
|
|
76
|
+
- Easy to extend with custom providers
|
|
77
|
+
|
|
78
|
+
📚 See [ARCHITECTURE.md](./ARCHITECTURE.md) for detailed technical documentation.
|
|
79
|
+
|
|
80
|
+
## 📖 Examples
|
|
81
|
+
|
|
82
|
+
See [EXAMPLES.md](./EXAMPLES.md) for detailed usage examples and workflows.
|
|
83
|
+
|
|
84
|
+
## 🔌 Available Providers
|
|
85
|
+
|
|
86
|
+
| Provider | Status | Package |
|
|
87
|
+
| ---------------- | -------------- | --------------------------------- |
|
|
88
|
+
| 📁 File System | ✅ Stable | \`@taskin/fs-task-provider\` |
|
|
89
|
+
| 🔴 Redmine | 🚧 Coming Soon | \`@taskin/redmine-task-provider\` |
|
|
90
|
+
| 🔵 Jira | 🚧 Coming Soon | \`@taskin/jira-task-provider\` |
|
|
91
|
+
| 🐙 GitHub Issues | 🚧 Coming Soon | \`@taskin/github-task-provider\` |
|
|
92
|
+
|
|
93
|
+
Want to create your own provider? See [ARCHITECTURE.md](./ARCHITECTURE.md#-criando-um-novo-provider).
|
|
94
|
+
|
|
95
|
+
## 🤝 Contributing
|
|
96
|
+
|
|
97
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
98
|
+
|
|
99
|
+
## 📝 Requirements
|
|
100
|
+
|
|
101
|
+
- Node.js >= 20.0.0
|
|
102
|
+
- npm/pnpm/yarn
|
|
103
|
+
|
|
104
|
+
## 🐛 Issues
|
|
105
|
+
|
|
106
|
+
Found a bug? Have a feature request? Please [open an issue](https://github.com/opentask-app/taskin/issues).
|
|
107
|
+
|
|
108
|
+
## � Team
|
|
109
|
+
|
|
110
|
+
**OpenTask**
|
|
111
|
+
- Website: [opentask.com.br](https://opentask.com.br)
|
|
112
|
+
- Email: contato@opentask.com.br
|
|
113
|
+
|
|
114
|
+
**Contributors:**
|
|
115
|
+
- Sidarta Veloso ([@sidartaveloso](https://github.com/sidartaveloso))
|
|
116
|
+
|
|
117
|
+
## 📄 License
|
|
118
|
+
|
|
119
|
+
MIT © [OpenTask](https://opentask.com.br)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI commands types
|
|
3
|
+
* Re-exports from @taskin/types-ts for convenience
|
|
4
|
+
*/
|
|
5
|
+
export type {
|
|
6
|
+
FinishTaskOptions,
|
|
7
|
+
ListTasksOptions,
|
|
8
|
+
PauseTaskOptions,
|
|
9
|
+
StartTaskOptions,
|
|
10
|
+
} from '@taskin/types-ts';
|
|
11
|
+
export interface LintOptions {
|
|
12
|
+
path?: string;
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.types.js","sourceRoot":"","sources":["../../src/commands/commands.types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command definition helper
|
|
3
|
+
* Provides a declarative way to define CLI commands
|
|
4
|
+
*/
|
|
5
|
+
import { error } from '../../lib/colors.js';
|
|
6
|
+
export const defineCommand = (config) => {
|
|
7
|
+
return (program) => {
|
|
8
|
+
const cmd = program.command(config.name).description(config.description);
|
|
9
|
+
if (config.alias) {
|
|
10
|
+
cmd.alias(config.alias);
|
|
11
|
+
}
|
|
12
|
+
config.options?.forEach((opt) => {
|
|
13
|
+
cmd.option(opt.flags, opt.description, opt.defaultValue);
|
|
14
|
+
});
|
|
15
|
+
cmd.action(async (...args) => {
|
|
16
|
+
try {
|
|
17
|
+
await config.handler(...args);
|
|
18
|
+
} catch (err) {
|
|
19
|
+
error(
|
|
20
|
+
`Failed to execute command: ${err instanceof Error ? err.message : String(err)}`,
|
|
21
|
+
);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=define-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-command.js","sourceRoot":"","sources":["../../../src/commands/define-command/define-command.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAG5C,MAAM,CAAC,MAAM,aAAa,GAA0B,CAAC,MAAM,EAAE,EAAE;IAC7D,OAAO,CAAC,OAAgB,EAAE,EAAE;QAC1B,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAEzE,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;QAED,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;YAC9B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC;QAEH,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,IAAI,EAAE,EAAE;YAC3B,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;YAChC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,KAAK,CACH,8BAA8B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACjF,CAAC;gBACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for defineCommand
|
|
3
|
+
*/
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
6
|
+
import { defineCommand } from './define-command.js';
|
|
7
|
+
describe('defineCommand', () => {
|
|
8
|
+
it('should create a command registration function', () => {
|
|
9
|
+
const handler = vi.fn();
|
|
10
|
+
const commandReg = defineCommand({
|
|
11
|
+
name: 'test',
|
|
12
|
+
description: 'Test command',
|
|
13
|
+
handler,
|
|
14
|
+
});
|
|
15
|
+
expect(commandReg).toBeTypeOf('function');
|
|
16
|
+
});
|
|
17
|
+
it('should register a command with the program', () => {
|
|
18
|
+
const program = new Command();
|
|
19
|
+
const handler = vi.fn();
|
|
20
|
+
const commandReg = defineCommand({
|
|
21
|
+
name: 'test',
|
|
22
|
+
description: 'Test command',
|
|
23
|
+
handler,
|
|
24
|
+
});
|
|
25
|
+
commandReg(program);
|
|
26
|
+
const commands = program.commands;
|
|
27
|
+
expect(commands).toHaveLength(1);
|
|
28
|
+
expect(commands[0]?.name()).toBe('test');
|
|
29
|
+
});
|
|
30
|
+
it('should register command with alias', () => {
|
|
31
|
+
const program = new Command();
|
|
32
|
+
const handler = vi.fn();
|
|
33
|
+
const commandReg = defineCommand({
|
|
34
|
+
name: 'test',
|
|
35
|
+
description: 'Test command',
|
|
36
|
+
alias: 't',
|
|
37
|
+
handler,
|
|
38
|
+
});
|
|
39
|
+
commandReg(program);
|
|
40
|
+
const command = program.commands[0];
|
|
41
|
+
expect(command?.alias()).toBe('t');
|
|
42
|
+
});
|
|
43
|
+
it('should register command with options', () => {
|
|
44
|
+
const program = new Command();
|
|
45
|
+
const handler = vi.fn();
|
|
46
|
+
const commandReg = defineCommand({
|
|
47
|
+
name: 'test',
|
|
48
|
+
description: 'Test command',
|
|
49
|
+
options: [
|
|
50
|
+
{
|
|
51
|
+
flags: '-f, --force',
|
|
52
|
+
description: 'Force flag',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
flags: '-n, --name <name>',
|
|
56
|
+
description: 'Name option',
|
|
57
|
+
defaultValue: 'default',
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
handler,
|
|
61
|
+
});
|
|
62
|
+
commandReg(program);
|
|
63
|
+
const command = program.commands[0];
|
|
64
|
+
const options = command?.options;
|
|
65
|
+
expect(options).toHaveLength(2);
|
|
66
|
+
expect(options?.[0]?.flags).toBe('-f, --force');
|
|
67
|
+
expect(options?.[1]?.flags).toBe('-n, --name <name>');
|
|
68
|
+
});
|
|
69
|
+
it('should call handler when command is executed', async () => {
|
|
70
|
+
const program = new Command();
|
|
71
|
+
const handler = vi.fn().mockResolvedValue(undefined);
|
|
72
|
+
const commandReg = defineCommand({
|
|
73
|
+
name: 'test <arg>',
|
|
74
|
+
description: 'Test command',
|
|
75
|
+
handler,
|
|
76
|
+
});
|
|
77
|
+
commandReg(program);
|
|
78
|
+
// Simulate command execution
|
|
79
|
+
await program.parseAsync(['node', 'test', 'test', 'myarg']);
|
|
80
|
+
expect(handler).toHaveBeenCalledWith(
|
|
81
|
+
'myarg',
|
|
82
|
+
expect.any(Object),
|
|
83
|
+
expect.any(Object),
|
|
84
|
+
);
|
|
85
|
+
});
|
|
86
|
+
it('should handle async handler errors', async () => {
|
|
87
|
+
const program = new Command();
|
|
88
|
+
const error = new Error('Test error');
|
|
89
|
+
const handler = vi.fn().mockRejectedValue(error);
|
|
90
|
+
const exitSpy = vi
|
|
91
|
+
.spyOn(process, 'exit')
|
|
92
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
93
|
+
.mockImplementation(() => {});
|
|
94
|
+
const commandReg = defineCommand({
|
|
95
|
+
name: 'test',
|
|
96
|
+
description: 'Test command',
|
|
97
|
+
handler,
|
|
98
|
+
});
|
|
99
|
+
commandReg(program);
|
|
100
|
+
await program.parseAsync(['node', 'test', 'test']);
|
|
101
|
+
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
102
|
+
exitSpy.mockRestore();
|
|
103
|
+
});
|
|
104
|
+
it('should handle sync handler errors', async () => {
|
|
105
|
+
const program = new Command();
|
|
106
|
+
const error = new Error('Test error');
|
|
107
|
+
const handler = vi.fn().mockImplementation(() => {
|
|
108
|
+
throw error;
|
|
109
|
+
});
|
|
110
|
+
const exitSpy = vi
|
|
111
|
+
.spyOn(process, 'exit')
|
|
112
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
113
|
+
.mockImplementation(() => {});
|
|
114
|
+
const commandReg = defineCommand({
|
|
115
|
+
name: 'test',
|
|
116
|
+
description: 'Test command',
|
|
117
|
+
handler,
|
|
118
|
+
});
|
|
119
|
+
commandReg(program);
|
|
120
|
+
await program.parseAsync(['node', 'test', 'test']);
|
|
121
|
+
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
122
|
+
exitSpy.mockRestore();
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
//# sourceMappingURL=define-command.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-command.test.js","sourceRoot":"","sources":["../../../src/commands/define-command/define-command.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command definition types
|
|
3
|
+
*/
|
|
4
|
+
import type { Command } from 'commander';
|
|
5
|
+
export interface CommandOption {
|
|
6
|
+
description: string;
|
|
7
|
+
flags: string;
|
|
8
|
+
defaultValue?: string | boolean | string[];
|
|
9
|
+
}
|
|
10
|
+
export interface CommandConfig {
|
|
11
|
+
description: string;
|
|
12
|
+
handler: (...args: any[]) => Promise<void> | void;
|
|
13
|
+
name: string;
|
|
14
|
+
alias?: string;
|
|
15
|
+
options?: CommandOption[];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Type for a command registration function
|
|
19
|
+
* Takes a Commander program and registers a command with it
|
|
20
|
+
*/
|
|
21
|
+
export type CommandRegistration = (program: Command) => void;
|
|
22
|
+
/**
|
|
23
|
+
* Type for the defineCommand function.
|
|
24
|
+
*
|
|
25
|
+
* Define a CLI command with declarative configuration.
|
|
26
|
+
* This function takes a command configuration object and returns a function
|
|
27
|
+
* that registers the command with a Commander program.
|
|
28
|
+
*
|
|
29
|
+
* @param config - Command configuration object containing name, description, options, and handler
|
|
30
|
+
* @returns Function that registers the command with a Commander program
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* export const listCommand = defineCommand({
|
|
35
|
+
* name: 'list [filter]',
|
|
36
|
+
* description: '📊 List all tasks',
|
|
37
|
+
* alias: 'ls',
|
|
38
|
+
* options: [
|
|
39
|
+
* { flags: '-s, --status <status>', description: 'Filter by status' }
|
|
40
|
+
* ],
|
|
41
|
+
* handler: async (filter, options) => {
|
|
42
|
+
* // Implementation
|
|
43
|
+
* }
|
|
44
|
+
* });
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export type DefineCommandFunction = (
|
|
48
|
+
config: CommandConfig,
|
|
49
|
+
) => CommandRegistration;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-command.types.js","sourceRoot":"","sources":["../../../src/commands/define-command/define-command.types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/define-command/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finish command - Complete a task
|
|
3
|
+
*/
|
|
4
|
+
import { FileSystemTaskProvider } from '@taskin/fs-task-provider';
|
|
5
|
+
import { TaskManager } from '@taskin/task-manager';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import { colors, error, info, printHeader, success } from '../lib/colors.js';
|
|
8
|
+
import { defineCommand } from './define-command/index.js';
|
|
9
|
+
export const finishCommand = defineCommand({
|
|
10
|
+
name: 'finish <task-id>',
|
|
11
|
+
description: '✅ Complete a task',
|
|
12
|
+
alias: 'done',
|
|
13
|
+
options: [
|
|
14
|
+
{
|
|
15
|
+
flags: '-s, --skip-update',
|
|
16
|
+
description: 'Skip updating task status',
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
handler: async (taskId, options) => {
|
|
20
|
+
await finishTask(taskId, options);
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
async function finishTask(taskId, options) {
|
|
24
|
+
printHeader(`Finishing Task ${taskId}`, '✅');
|
|
25
|
+
// Normalize task ID
|
|
26
|
+
const normalizedId = taskId.replace(/^task-/, '').padStart(3, '0');
|
|
27
|
+
// Find TASKS directory
|
|
28
|
+
const tasksDir = path.join(process.cwd(), 'TASKS');
|
|
29
|
+
// Initialize task manager
|
|
30
|
+
const taskProvider = new FileSystemTaskProvider(tasksDir);
|
|
31
|
+
const taskManager = new TaskManager(taskProvider);
|
|
32
|
+
// Find task
|
|
33
|
+
const task = await taskProvider.findTask(normalizedId);
|
|
34
|
+
if (!task) {
|
|
35
|
+
error(`Task ${normalizedId} not found in TASKS/ directory`);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
info(`Found task: ${task.title}`);
|
|
39
|
+
info(`Current status: ${task.status}`);
|
|
40
|
+
// Check if task is already done
|
|
41
|
+
if (task.status === 'done') {
|
|
42
|
+
error('Task is already done');
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
if (!options.skipUpdate) {
|
|
46
|
+
info('Marking task as done...');
|
|
47
|
+
const updatedTask = await taskManager.finishTask(task.id);
|
|
48
|
+
success(`Task ${updatedTask.id} completed successfully! 🎉`);
|
|
49
|
+
success(`Status changed to: ${updatedTask.status}`);
|
|
50
|
+
} else {
|
|
51
|
+
info('Skipping status update (--skip-update flag)');
|
|
52
|
+
}
|
|
53
|
+
console.log();
|
|
54
|
+
info('Suggested commit message:');
|
|
55
|
+
const commitType = task.type || 'feat';
|
|
56
|
+
console.log(
|
|
57
|
+
colors.highlight(` ${commitType}(task-${normalizedId}): ${task.title}`),
|
|
58
|
+
);
|
|
59
|
+
console.log();
|
|
60
|
+
info('Next steps:');
|
|
61
|
+
console.log(colors.secondary(' 1. Review your changes'));
|
|
62
|
+
console.log(colors.secondary(' 2. Commit: git add . && git commit'));
|
|
63
|
+
console.log(colors.secondary(' 3. Push: git push'));
|
|
64
|
+
console.log(colors.secondary(' 4. Create a Pull Request'));
|
|
65
|
+
console.log();
|
|
66
|
+
success('Great work! 🚀');
|
|
67
|
+
console.log();
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=finish.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finish.js","sourceRoot":"","sources":["../../src/commands/finish.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC"}
|