@opentask/taskin-task-manager 1.0.6
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/.turbo/turbo-build.log +5 -0
- package/.turbo/turbo-format.log +31 -0
- package/.turbo/turbo-test.log +15 -0
- package/CHANGELOG.md +7 -0
- package/README.md +84 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/metrics.types.d.ts +92 -0
- package/dist/metrics.types.js +2 -0
- package/dist/metrics.types.js.map +1 -0
- package/dist/provider-stats.test.d.ts +1 -0
- package/dist/provider-stats.test.js +17 -0
- package/dist/provider-stats.test.js.map +1 -0
- package/dist/task-manager.d.ts +16 -0
- package/dist/task-manager.js +37 -0
- package/dist/task-manager.js.map +1 -0
- package/dist/task-manager.mock.d.ts +5 -0
- package/dist/task-manager.mock.js +21 -0
- package/dist/task-manager.mock.js.map +1 -0
- package/dist/task-manager.test.d.ts +1 -0
- package/dist/task-manager.test.js +104 -0
- package/dist/task-manager.test.js.map +1 -0
- package/dist/task-manager.types.d.ts +152 -0
- package/dist/task-manager.types.js +2 -0
- package/dist/task-manager.types.js.map +1 -0
- package/eslint.config.js +8 -0
- package/package.json +52 -0
- package/src/index.ts +5 -0
- package/src/metrics.types.ts +96 -0
- package/src/provider-stats.test.ts +20 -0
- package/src/task-manager.mock.ts +24 -0
- package/src/task-manager.test.ts +133 -0
- package/src/task-manager.ts +54 -0
- package/src/task-manager.types.ts +167 -0
- package/tsconfig.json +11 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/vitest.config.ts +7 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
> @opentask/taskin-task-manager@1.0.5 format /Users/sidarta/repositorios/taskin/packages/task-manager
|
|
4
|
+
> prettier --write .
|
|
5
|
+
|
|
6
|
+
.turbo/turbo-build.log[2K[1G.turbo/turbo-format.log[2K[1G.turbo/turbo-test.log[2K[1Gdist/index.d.ts[2K[1G[90mdist/index.d.ts[39m 59ms (unchanged)
|
|
7
|
+
dist/index.js[2K[1G[90mdist/index.js[39m 12ms (unchanged)
|
|
8
|
+
dist/index.js.map[2K[1Gdist/metrics.types.d.ts[2K[1G[90mdist/metrics.types.d.ts[39m 19ms (unchanged)
|
|
9
|
+
dist/metrics.types.js[2K[1G[90mdist/metrics.types.js[39m 3ms (unchanged)
|
|
10
|
+
dist/metrics.types.js.map[2K[1Gdist/provider-stats.test.d.ts[2K[1G[90mdist/provider-stats.test.d.ts[39m 2ms (unchanged)
|
|
11
|
+
dist/provider-stats.test.js[2K[1G[90mdist/provider-stats.test.js[39m 13ms (unchanged)
|
|
12
|
+
dist/provider-stats.test.js.map[2K[1Gdist/task-manager.d.ts[2K[1G[90mdist/task-manager.d.ts[39m 8ms (unchanged)
|
|
13
|
+
dist/task-manager.js[2K[1G[90mdist/task-manager.js[39m 19ms (unchanged)
|
|
14
|
+
dist/task-manager.js.map[2K[1Gdist/task-manager.mock.d.ts[2K[1G[90mdist/task-manager.mock.d.ts[39m 8ms (unchanged)
|
|
15
|
+
dist/task-manager.mock.js[2K[1G[90mdist/task-manager.mock.js[39m 6ms (unchanged)
|
|
16
|
+
dist/task-manager.mock.js.map[2K[1Gdist/task-manager.test.d.ts[2K[1G[90mdist/task-manager.test.d.ts[39m 5ms (unchanged)
|
|
17
|
+
dist/task-manager.test.js[2K[1G[90mdist/task-manager.test.js[39m 25ms (unchanged)
|
|
18
|
+
dist/task-manager.test.js.map[2K[1Gdist/task-manager.types.d.ts[2K[1G[90mdist/task-manager.types.d.ts[39m 19ms (unchanged)
|
|
19
|
+
dist/task-manager.types.js[2K[1G[90mdist/task-manager.types.js[39m 2ms (unchanged)
|
|
20
|
+
dist/task-manager.types.js.map[2K[1Geslint.config.js[2K[1G[90meslint.config.js[39m 9ms (unchanged)
|
|
21
|
+
package.json[2K[1G[90mpackage.json[39m 7ms (unchanged)
|
|
22
|
+
README.md[2K[1G[90mREADME.md[39m 26ms (unchanged)
|
|
23
|
+
src/index.ts[2K[1G[90msrc/index.ts[39m 4ms (unchanged)
|
|
24
|
+
src/metrics.types.ts[2K[1G[90msrc/metrics.types.ts[39m 14ms (unchanged)
|
|
25
|
+
src/provider-stats.test.ts[2K[1G[90msrc/provider-stats.test.ts[39m 8ms (unchanged)
|
|
26
|
+
src/task-manager.mock.ts[2K[1G[90msrc/task-manager.mock.ts[39m 13ms (unchanged)
|
|
27
|
+
src/task-manager.test.ts[2K[1G[90msrc/task-manager.test.ts[39m 48ms (unchanged)
|
|
28
|
+
src/task-manager.ts[2K[1G[90msrc/task-manager.ts[39m 27ms (unchanged)
|
|
29
|
+
src/task-manager.types.ts[2K[1G[90msrc/task-manager.types.ts[39m 9ms (unchanged)
|
|
30
|
+
tsconfig.json[2K[1G[90mtsconfig.json[39m 2ms (unchanged)
|
|
31
|
+
tsconfig.tsbuildinfo[2K[1Gvitest.config.ts[2K[1G[90mvitest.config.ts[39m 4ms (unchanged)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
> @opentask/taskin-task-manager@1.0.5 test /Users/sidarta/repositorios/taskin/packages/task-manager
|
|
3
|
+
> vitest run
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
[1m[46m RUN [49m[22m [36mv4.0.16 [39m[90m/Users/sidarta/repositorios/taskin/packages/task-manager[39m
|
|
7
|
+
|
|
8
|
+
[32m✓[39m src/provider-stats.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 1[2mms[22m[39m
|
|
9
|
+
[32m✓[39m src/task-manager.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 60[2mms[22m[39m
|
|
10
|
+
|
|
11
|
+
[2m Test Files [22m [1m[32m2 passed[39m[22m[90m (2)[39m
|
|
12
|
+
[2m Tests [22m [1m[32m10 passed[39m[22m[90m (10)[39m
|
|
13
|
+
[2m Start at [22m 09:48:51
|
|
14
|
+
[2m Duration [22m 496ms[2m (transform 59ms, setup 0ms, import 108ms, tests 62ms, environment 0ms)[22m
|
|
15
|
+
|
package/CHANGELOG.md
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Task Manager — Metrics Interface
|
|
2
|
+
|
|
3
|
+
This document describes the new `IMetricsManager` interface introduced to
|
|
4
|
+
separate metrics/analytics responsibilities from the core `ITaskProvider`.
|
|
5
|
+
|
|
6
|
+
## Motivation
|
|
7
|
+
|
|
8
|
+
Previously the `ITaskProvider` exposed optional methods for statistics
|
|
9
|
+
(`getUserStats`, `getTeamStats`, `getTaskStats`). To keep provider
|
|
10
|
+
implementations focused on storage concerns and to provide a clearer
|
|
11
|
+
contract for analytics, we introduced `IMetricsManager` as a dedicated
|
|
12
|
+
interface for metrics/analytics.
|
|
13
|
+
|
|
14
|
+
## Interface
|
|
15
|
+
|
|
16
|
+
The interface lives at `packages/task-manager/src/metrics.types.ts`:
|
|
17
|
+
|
|
18
|
+
- `getUserMetrics(userId: string, query?: StatsQuery): Promise<UserStats>`
|
|
19
|
+
- `getTeamMetrics(teamId: string, query?: StatsQuery): Promise<TeamStats>`
|
|
20
|
+
- `getTaskMetrics(taskId: string, query?: StatsQuery): Promise<TaskStats>`
|
|
21
|
+
|
|
22
|
+
Types are re-used from `@opentask/taskin-types` (`UserStats`, `TeamStats`,
|
|
23
|
+
`TaskStats`, `StatsQuery`).
|
|
24
|
+
|
|
25
|
+
## Migration guide
|
|
26
|
+
|
|
27
|
+
1. Remove any optional stats methods from provider implementations. The
|
|
28
|
+
methods were removed from `ITaskProvider` to avoid mixing concerns.
|
|
29
|
+
2. Implement an adapter/service that implements `IMetricsManager` and
|
|
30
|
+
register it alongside your provider (for example, provide it to the
|
|
31
|
+
application bootstrap or dependency injection container).
|
|
32
|
+
3. If you need to preserve backward compatibility, expose a thin adapter
|
|
33
|
+
that translates the old provider-level methods to the new
|
|
34
|
+
`IMetricsManager` API until consumers migrate.
|
|
35
|
+
|
|
36
|
+
## Example
|
|
37
|
+
|
|
38
|
+
Minimal example of an in-process metrics adapter (pseudo-code):
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import type { IMetricsManager } from '@opentask/taskin-task-manager';
|
|
42
|
+
import type { UserStats, StatsQuery } from '@opentask/taskin-types';
|
|
43
|
+
|
|
44
|
+
export class FsMetricsAdapter implements IMetricsManager {
|
|
45
|
+
constructor(private fsProvider: any) {}
|
|
46
|
+
|
|
47
|
+
async getUserMetrics(userId: string, query?: StatsQuery): Promise<UserStats> {
|
|
48
|
+
// Aggregate tasks from fsProvider and compute simple metrics
|
|
49
|
+
const tasks = await this.fsProvider.getAllTasks();
|
|
50
|
+
const userTasks = tasks.filter((t) => t.assignee?.id === userId);
|
|
51
|
+
return { userId, taskCount: userTasks.length } as any;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// getTeamMetrics / getTaskMetrics implementations...
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Compatibility and Versioning
|
|
59
|
+
|
|
60
|
+
- This change is a breaking API change for providers: `ITaskProvider`
|
|
61
|
+
no longer contains stats methods. New providers should implement
|
|
62
|
+
`IMetricsManager` instead.
|
|
63
|
+
- For consumers, prefer depending on `IMetricsManager` for analytics
|
|
64
|
+
features. If a provider exposes metrics through a different channel,
|
|
65
|
+
adapt it to `IMetricsManager`.
|
|
66
|
+
|
|
67
|
+
## Tests
|
|
68
|
+
|
|
69
|
+
There is a small unit test validating the contract at
|
|
70
|
+
`packages/task-manager/src/provider-stats.test.ts` (now checks the
|
|
71
|
+
`IMetricsManager` shape).
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
If you want, I can:
|
|
76
|
+
|
|
77
|
+
- Add an example adapter implementation in `file-system-task-provider`.
|
|
78
|
+
- Add documentation to the repo-level `docs/` folder and cross-links.
|
|
79
|
+
|
|
80
|
+
Tell me which and I’ll implement it.
|
|
81
|
+
|
|
82
|
+
# @taskin/task-manager
|
|
83
|
+
|
|
84
|
+
This package is responsible for the core logic of managing tasks.
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
StatsQuery,
|
|
3
|
+
TaskStats,
|
|
4
|
+
TeamStats,
|
|
5
|
+
UserStats,
|
|
6
|
+
} from '@opentask/taskin-types';
|
|
7
|
+
/**
|
|
8
|
+
* Manages metrics and statistics for users, teams, and tasks.
|
|
9
|
+
* Aggregates data from Git history and task files to provide productivity insights.
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
* This interface separates analytics/reporting responsibilities from ITaskProvider,
|
|
13
|
+
* following the Single Responsibility Principle.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* const metrics = new FileSystemMetricsAdapter(tasksDir, userRegistry, gitAnalyzer);
|
|
18
|
+
* const stats = await metrics.getUserMetrics('john-doe', { period: 'week' });
|
|
19
|
+
* console.log(`Commits: ${stats.codeMetrics.commits}`);
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
export interface IMetricsManager {
|
|
25
|
+
/**
|
|
26
|
+
* Get productivity metrics for a specific user.
|
|
27
|
+
*
|
|
28
|
+
* Includes code metrics (commits, lines of code), temporal patterns
|
|
29
|
+
* (day of week, time of day), and engagement statistics (completion rate, streaks).
|
|
30
|
+
*
|
|
31
|
+
* @param userId - User identifier (username or registry ID)
|
|
32
|
+
* @param query - Optional query parameters to filter results
|
|
33
|
+
* @param query.period - Time period to analyze ('day' | 'week' | 'month' | 'year')
|
|
34
|
+
* @returns Promise resolving to user statistics
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* const stats = await metrics.getUserMetrics('alice', { period: 'month' });
|
|
39
|
+
* console.log(`Tasks completed: ${stats.contributionMetrics.tasksCompleted}`);
|
|
40
|
+
* console.log(`Completion rate: ${(stats.engagementMetrics.completionRate * 100).toFixed(1)}%`);
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
getUserMetrics(userId: string, query?: StatsQuery): Promise<UserStats>;
|
|
44
|
+
/**
|
|
45
|
+
* Get aggregated metrics for an entire team.
|
|
46
|
+
*
|
|
47
|
+
* Provides overview of team productivity with breakdown by individual contributors.
|
|
48
|
+
* Useful for team retrospectives, capacity planning, and identifying top contributors.
|
|
49
|
+
*
|
|
50
|
+
* @param teamId - Team identifier
|
|
51
|
+
* @param query - Optional query parameters to filter results
|
|
52
|
+
* @returns Promise resolving to team statistics with per-contributor breakdown
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* const stats = await metrics.getTeamMetrics('frontend', { period: 'week' });
|
|
57
|
+
* console.log(`Total commits: ${stats.totalCommits}`);
|
|
58
|
+
* console.log(`Contributors: ${stats.totalContributors}`);
|
|
59
|
+
* stats.contributors.forEach(c => {
|
|
60
|
+
* console.log(`${c.username}: ${c.commits} commits, ${c.tasksCompleted} tasks`);
|
|
61
|
+
* });
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
getTeamMetrics(teamId: string, query?: StatsQuery): Promise<TeamStats>;
|
|
65
|
+
/**
|
|
66
|
+
* Get detailed metrics for a specific task.
|
|
67
|
+
*
|
|
68
|
+
* Includes timeline analysis, contributor activity, code impact metrics,
|
|
69
|
+
* and work patterns. Useful for task retrospectives and understanding
|
|
70
|
+
* effort distribution.
|
|
71
|
+
*
|
|
72
|
+
* @param taskId - Task identifier (task number like '015' or full ID like 'task-015')
|
|
73
|
+
* @param query - Optional query parameters
|
|
74
|
+
* @returns Promise resolving to task-specific statistics
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```ts
|
|
78
|
+
* const stats = await metrics.getTaskMetrics('task-015', {});
|
|
79
|
+
* console.log(`Duration: ${stats.duration} days`);
|
|
80
|
+
* console.log(`Contributors: ${stats.contributors.map(c => c.name).join(', ')}`);
|
|
81
|
+
* if (stats.refactoringMetrics) {
|
|
82
|
+
* console.log(`Simplification ratio: ${stats.refactoringMetrics.simplificationRatio.toFixed(2)}x`);
|
|
83
|
+
* }
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
getTaskMetrics(taskId: string, query?: StatsQuery): Promise<TaskStats>;
|
|
87
|
+
}
|
|
88
|
+
export type {
|
|
89
|
+
TaskStats as TaskMetrics,
|
|
90
|
+
TeamStats as TeamMetrics,
|
|
91
|
+
UserStats as UserMetrics,
|
|
92
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.types.js","sourceRoot":"","sources":["../src/metrics.types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
describe('IMetricsManager contract', () => {
|
|
3
|
+
it('accepts an object implementing IMetricsManager', async () => {
|
|
4
|
+
const metrics = {
|
|
5
|
+
getUserMetrics: async (userId) => ({ userId }),
|
|
6
|
+
getTeamMetrics: async (teamId) => ({ teamId }),
|
|
7
|
+
getTaskMetrics: async (taskId) => ({ taskId }),
|
|
8
|
+
};
|
|
9
|
+
expect(typeof metrics.getUserMetrics).toBe('function');
|
|
10
|
+
expect(typeof metrics.getTeamMetrics).toBe('function');
|
|
11
|
+
expect(typeof metrics.getTaskMetrics).toBe('function');
|
|
12
|
+
await expect(metrics.getUserMetrics('u1')).resolves.toBeDefined();
|
|
13
|
+
await expect(metrics.getTeamMetrics('t1')).resolves.toBeDefined();
|
|
14
|
+
await expect(metrics.getTaskMetrics('task1')).resolves.toBeDefined();
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
//# sourceMappingURL=provider-stats.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-stats.test.js","sourceRoot":"","sources":["../src/provider-stats.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAG9C,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,OAAO,GAAoB;YAC/B,cAAc,EAAE,KAAK,EAAE,MAAc,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAQ;YAC7D,cAAc,EAAE,KAAK,EAAE,MAAc,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAQ;YAC7D,cAAc,EAAE,KAAK,EAAE,MAAc,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAQ;SAC9D,CAAC;QAEF,MAAM,CAAC,OAAO,OAAO,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACvD,MAAM,CAAC,OAAO,OAAO,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACvD,MAAM,CAAC,OAAO,OAAO,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAEvD,MAAM,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;QAClE,MAAM,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;QAClE,MAAM,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;IACvE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CreateTaskOptions,
|
|
3
|
+
CreateTaskResult,
|
|
4
|
+
ITaskManager,
|
|
5
|
+
ITaskProvider,
|
|
6
|
+
LintResult,
|
|
7
|
+
TaskFile,
|
|
8
|
+
} from './task-manager.types';
|
|
9
|
+
export declare class TaskManager implements ITaskManager {
|
|
10
|
+
private taskProvider;
|
|
11
|
+
constructor(taskProvider: ITaskProvider);
|
|
12
|
+
startTask(taskId: string): Promise<TaskFile>;
|
|
13
|
+
finishTask(taskId: string): Promise<TaskFile>;
|
|
14
|
+
createTask(options: CreateTaskOptions): Promise<CreateTaskResult>;
|
|
15
|
+
lint(fix?: boolean): Promise<LintResult>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export class TaskManager {
|
|
2
|
+
taskProvider;
|
|
3
|
+
constructor(taskProvider) {
|
|
4
|
+
this.taskProvider = taskProvider;
|
|
5
|
+
}
|
|
6
|
+
async startTask(taskId) {
|
|
7
|
+
const task = await this.taskProvider.findTask(taskId);
|
|
8
|
+
if (!task) {
|
|
9
|
+
throw new Error(`Task with ID '${taskId}' not found.`);
|
|
10
|
+
}
|
|
11
|
+
if (task.status === 'in-progress') {
|
|
12
|
+
throw new Error(`Task '${taskId}' is already in progress.`);
|
|
13
|
+
}
|
|
14
|
+
if (task.status === 'done') {
|
|
15
|
+
throw new Error(`Task '${taskId}' is already done.`);
|
|
16
|
+
}
|
|
17
|
+
const updatedTask = { ...task, status: 'in-progress' };
|
|
18
|
+
await this.taskProvider.updateTask(updatedTask);
|
|
19
|
+
return updatedTask;
|
|
20
|
+
}
|
|
21
|
+
async finishTask(taskId) {
|
|
22
|
+
const task = await this.taskProvider.findTask(taskId);
|
|
23
|
+
if (!task) {
|
|
24
|
+
throw new Error(`Task with ID '${taskId}' not found.`);
|
|
25
|
+
}
|
|
26
|
+
const updatedTask = { ...task, status: 'done' };
|
|
27
|
+
await this.taskProvider.updateTask(updatedTask);
|
|
28
|
+
return updatedTask;
|
|
29
|
+
}
|
|
30
|
+
async createTask(options) {
|
|
31
|
+
return this.taskProvider.createTask(options);
|
|
32
|
+
}
|
|
33
|
+
async lint(fix) {
|
|
34
|
+
return this.taskProvider.lint(fix);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=task-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-manager.js","sourceRoot":"","sources":["../src/task-manager.ts"],"names":[],"mappings":"AASA,MAAM,OAAO,WAAW;IACF;IAApB,YAAoB,YAA2B;QAA3B,iBAAY,GAAZ,YAAY,CAAe;IAAG,CAAC;IAEnD,KAAK,CAAC,SAAS,CAAC,MAAc;QAC5B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAEtD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,iBAAiB,MAAM,cAAc,CAAC,CAAC;QACzD,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,KAAK,aAAa,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC,SAAS,MAAM,2BAA2B,CAAC,CAAC;QAC9D,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,SAAS,MAAM,oBAAoB,CAAC,CAAC;QACvD,CAAC;QAED,MAAM,WAAW,GAAa,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;QACjE,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;QAEhD,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,MAAc;QAC7B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAEtD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,iBAAiB,MAAM,cAAc,CAAC,CAAC;QACzD,CAAC;QAED,MAAM,WAAW,GAAa,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAC1D,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;QAEhD,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,OAA0B;QACzC,OAAO,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,GAAa;QACtB,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrC,CAAC;CACF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { vi } from 'vitest';
|
|
2
|
+
export const createMockTask = (overrides) => ({
|
|
3
|
+
content: '# Task 001 - Implement feature',
|
|
4
|
+
createdAt: new Date().toISOString(),
|
|
5
|
+
description: 'A test feature',
|
|
6
|
+
filePath: '/tasks/task-001.md',
|
|
7
|
+
id: 'task-001',
|
|
8
|
+
status: 'pending',
|
|
9
|
+
title: 'Implement feature',
|
|
10
|
+
type: 'feat',
|
|
11
|
+
userId: 'user-123',
|
|
12
|
+
...overrides,
|
|
13
|
+
});
|
|
14
|
+
export const createMockTaskProvider = () => ({
|
|
15
|
+
findTask: vi.fn(),
|
|
16
|
+
getAllTasks: vi.fn(),
|
|
17
|
+
updateTask: vi.fn(),
|
|
18
|
+
createTask: vi.fn(),
|
|
19
|
+
lint: vi.fn(),
|
|
20
|
+
});
|
|
21
|
+
//# sourceMappingURL=task-manager.mock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-manager.mock.js","sourceRoot":"","sources":["../src/task-manager.mock.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAG5B,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,SAA6B,EAAY,EAAE,CAAC,CAAC;IAC1E,OAAO,EAAE,gCAAgC;IACzC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;IACnC,WAAW,EAAE,gBAAgB;IAC7B,QAAQ,EAAE,oBAAoB;IAC9B,EAAE,EAAE,UAAqC;IACzC,MAAM,EAAE,SAAS;IACjB,KAAK,EAAE,mBAAmB;IAC1B,IAAI,EAAE,MAAM;IACZ,MAAM,EAAE,UAAU;IAClB,GAAG,SAAS;CACb,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAkB,EAAE,CAAC,CAAC;IAC1D,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE;IACjB,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE;IACpB,UAAU,EAAE,EAAE,CAAC,EAAE,EAAE;IACnB,UAAU,EAAE,EAAE,CAAC,EAAE,EAAE;IACnB,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE;CACd,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { TaskManager } from './task-manager';
|
|
3
|
+
import { createMockTask, createMockTaskProvider } from './task-manager.mock';
|
|
4
|
+
describe('TaskManager', () => {
|
|
5
|
+
let taskManager;
|
|
6
|
+
let mockTaskProvider;
|
|
7
|
+
let mockTask;
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
vi.clearAllMocks();
|
|
10
|
+
mockTaskProvider = createMockTaskProvider();
|
|
11
|
+
mockTask = createMockTask();
|
|
12
|
+
taskManager = new TaskManager(mockTaskProvider);
|
|
13
|
+
});
|
|
14
|
+
describe('startTask', () => {
|
|
15
|
+
it('should start a pending task', async () => {
|
|
16
|
+
mockTaskProvider.findTask.mockResolvedValue(mockTask);
|
|
17
|
+
const updatedTask = await taskManager.startTask('task-001');
|
|
18
|
+
expect(mockTaskProvider.findTask).toHaveBeenCalledWith('task-001');
|
|
19
|
+
expect(mockTaskProvider.updateTask).toHaveBeenCalledWith(
|
|
20
|
+
expect.objectContaining({ status: 'in-progress' }),
|
|
21
|
+
);
|
|
22
|
+
expect(updatedTask.status).toBe('in-progress');
|
|
23
|
+
});
|
|
24
|
+
it('should throw an error if task is not found', async () => {
|
|
25
|
+
mockTaskProvider.findTask.mockResolvedValue(undefined);
|
|
26
|
+
await expect(taskManager.startTask('not-found')).rejects.toThrow(
|
|
27
|
+
"Task with ID 'not-found' not found.",
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
|
+
it('should throw an error if task is already in progress', async () => {
|
|
31
|
+
const inProgressTask = { ...mockTask, status: 'in-progress' };
|
|
32
|
+
mockTaskProvider.findTask.mockResolvedValue(inProgressTask);
|
|
33
|
+
await expect(taskManager.startTask('task-001')).rejects.toThrow(
|
|
34
|
+
"Task 'task-001' is already in progress.",
|
|
35
|
+
);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
describe('finishTask', () => {
|
|
39
|
+
it('should finish an in-progress task', async () => {
|
|
40
|
+
const inProgressTask = { ...mockTask, status: 'in-progress' };
|
|
41
|
+
mockTaskProvider.findTask.mockResolvedValue(inProgressTask);
|
|
42
|
+
const updatedTask = await taskManager.finishTask('task-001');
|
|
43
|
+
expect(mockTaskProvider.updateTask).toHaveBeenCalledWith(
|
|
44
|
+
expect.objectContaining({ status: 'done' }),
|
|
45
|
+
);
|
|
46
|
+
expect(updatedTask.status).toBe('done');
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
describe('createTask', () => {
|
|
50
|
+
it('should delegate task creation to provider', async () => {
|
|
51
|
+
const createOptions = { title: 'New Task', type: 'feat' };
|
|
52
|
+
const createResult = {
|
|
53
|
+
task: mockTask,
|
|
54
|
+
taskId: '001',
|
|
55
|
+
filePath: '/tasks/task-001.md',
|
|
56
|
+
};
|
|
57
|
+
mockTaskProvider.createTask.mockResolvedValue(createResult);
|
|
58
|
+
const result = await taskManager.createTask(createOptions);
|
|
59
|
+
expect(mockTaskProvider.createTask).toHaveBeenCalledWith(createOptions);
|
|
60
|
+
expect(result).toEqual(createResult);
|
|
61
|
+
});
|
|
62
|
+
it('should pass through description and assignee to provider', async () => {
|
|
63
|
+
const createOptions = {
|
|
64
|
+
title: 'New Task',
|
|
65
|
+
type: 'fix',
|
|
66
|
+
description: 'Fix something',
|
|
67
|
+
assignee: 'john-doe',
|
|
68
|
+
};
|
|
69
|
+
const createResult = {
|
|
70
|
+
task: mockTask,
|
|
71
|
+
taskId: '002',
|
|
72
|
+
filePath: '/tasks/task-002.md',
|
|
73
|
+
};
|
|
74
|
+
mockTaskProvider.createTask.mockResolvedValue(createResult);
|
|
75
|
+
const result = await taskManager.createTask(createOptions);
|
|
76
|
+
expect(mockTaskProvider.createTask).toHaveBeenCalledWith(createOptions);
|
|
77
|
+
expect(result.taskId).toBe('002');
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe('lint', () => {
|
|
81
|
+
it('should delegate lint without fix to provider', async () => {
|
|
82
|
+
const lintResult = { errors: 0, warnings: 2, details: [] };
|
|
83
|
+
mockTaskProvider.lint.mockResolvedValue(lintResult);
|
|
84
|
+
const result = await taskManager.lint();
|
|
85
|
+
expect(mockTaskProvider.lint).toHaveBeenCalledWith(undefined);
|
|
86
|
+
expect(result).toEqual(lintResult);
|
|
87
|
+
});
|
|
88
|
+
it('should delegate lint with fix=true to provider', async () => {
|
|
89
|
+
const lintResult = { errors: 0, warnings: 0, details: [] };
|
|
90
|
+
mockTaskProvider.lint.mockResolvedValue(lintResult);
|
|
91
|
+
const result = await taskManager.lint(true);
|
|
92
|
+
expect(mockTaskProvider.lint).toHaveBeenCalledWith(true);
|
|
93
|
+
expect(result).toEqual(lintResult);
|
|
94
|
+
});
|
|
95
|
+
it('should delegate lint with fix=false to provider', async () => {
|
|
96
|
+
const lintResult = { errors: 1, warnings: 2, details: [] };
|
|
97
|
+
mockTaskProvider.lint.mockResolvedValue(lintResult);
|
|
98
|
+
const result = await taskManager.lint(false);
|
|
99
|
+
expect(mockTaskProvider.lint).toHaveBeenCalledWith(false);
|
|
100
|
+
expect(result).toEqual(lintResult);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
//# sourceMappingURL=task-manager.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-manager.test.js","sourceRoot":"","sources":["../src/task-manager.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import type { Task, TaskType, User } from '@opentask/taskin-types';
|
|
2
|
+
/**
|
|
3
|
+
* Options for creating a new task
|
|
4
|
+
* @public
|
|
5
|
+
*/
|
|
6
|
+
export interface CreateTaskOptions {
|
|
7
|
+
/** Task title */
|
|
8
|
+
title: string;
|
|
9
|
+
/** Task type (feat, fix, chore, etc.) */
|
|
10
|
+
type: TaskType;
|
|
11
|
+
/** Optional task description */
|
|
12
|
+
description?: string;
|
|
13
|
+
/** Optional assignee user ID or name */
|
|
14
|
+
assignee?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Result of creating a new task
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
20
|
+
export interface CreateTaskResult {
|
|
21
|
+
/** The created task */
|
|
22
|
+
task: TaskFile;
|
|
23
|
+
/** The generated task ID */
|
|
24
|
+
taskId: string;
|
|
25
|
+
/** The file path where the task was created */
|
|
26
|
+
filePath: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Severity level for validation issues
|
|
30
|
+
* @public
|
|
31
|
+
*/
|
|
32
|
+
export type ValidationSeverity = 'error' | 'warning' | 'info';
|
|
33
|
+
/**
|
|
34
|
+
* A validation error or warning found during linting
|
|
35
|
+
* @public
|
|
36
|
+
*/
|
|
37
|
+
export interface ValidationIssue {
|
|
38
|
+
/** The file or task that has the issue */
|
|
39
|
+
file: string;
|
|
40
|
+
/** Optional line number where the issue occurs */
|
|
41
|
+
line?: number;
|
|
42
|
+
/** Human-readable description of the issue */
|
|
43
|
+
message: string;
|
|
44
|
+
/** Severity level of the issue */
|
|
45
|
+
severity: ValidationSeverity;
|
|
46
|
+
/** Optional suggestion for fixing the issue */
|
|
47
|
+
suggestion?: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Result of a lint operation
|
|
51
|
+
* @public
|
|
52
|
+
*/
|
|
53
|
+
export interface LintResult {
|
|
54
|
+
/** Whether the lint passed without errors */
|
|
55
|
+
valid: boolean;
|
|
56
|
+
/** List of validation issues found */
|
|
57
|
+
issues: ValidationIssue[];
|
|
58
|
+
/** Number of errors found */
|
|
59
|
+
errorCount: number;
|
|
60
|
+
/** Number of warnings found */
|
|
61
|
+
warningCount: number;
|
|
62
|
+
/** Number of info messages */
|
|
63
|
+
infoCount: number;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* A task with additional file system metadata.
|
|
67
|
+
* Extends the base Task type with content and path information.
|
|
68
|
+
* @public
|
|
69
|
+
*/
|
|
70
|
+
export type TaskFile = Task & {
|
|
71
|
+
/** The raw markdown content of the task file */
|
|
72
|
+
content: string;
|
|
73
|
+
/** Absolute or relative path to the task file */
|
|
74
|
+
filePath: string;
|
|
75
|
+
/** The type of work this task represents */
|
|
76
|
+
type: TaskType;
|
|
77
|
+
/** Optional user assigned to this task */
|
|
78
|
+
assignee?: User;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Interface for task storage providers.
|
|
82
|
+
* Implementations handle reading and writing tasks from different sources
|
|
83
|
+
* (e.g., file system, database, API).
|
|
84
|
+
* @public
|
|
85
|
+
*/
|
|
86
|
+
export interface ITaskProvider {
|
|
87
|
+
/**
|
|
88
|
+
* Find a specific task by its ID.
|
|
89
|
+
* @param taskId - The unique identifier of the task
|
|
90
|
+
* @returns The task if found, undefined otherwise
|
|
91
|
+
*/
|
|
92
|
+
findTask(taskId: string): Promise<TaskFile | undefined>;
|
|
93
|
+
/**
|
|
94
|
+
* Retrieve all tasks from the provider.
|
|
95
|
+
* @returns Array of all tasks
|
|
96
|
+
*/
|
|
97
|
+
getAllTasks(): Promise<TaskFile[]>;
|
|
98
|
+
/**
|
|
99
|
+
* Update an existing task.
|
|
100
|
+
* @param task - The task with updated information
|
|
101
|
+
*/
|
|
102
|
+
updateTask(task: TaskFile): Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* Create a new task.
|
|
105
|
+
* @param options - Options for creating the task
|
|
106
|
+
* @returns The created task information
|
|
107
|
+
*/
|
|
108
|
+
createTask(options: CreateTaskOptions): Promise<CreateTaskResult>;
|
|
109
|
+
/**
|
|
110
|
+
* Validate all tasks managed by this provider.
|
|
111
|
+
* Each provider knows its own format and validation rules.
|
|
112
|
+
* @param fix - If true, attempt to automatically fix validation issues
|
|
113
|
+
* @returns The lint result with any validation issues found
|
|
114
|
+
*/
|
|
115
|
+
lint(fix?: boolean): Promise<LintResult>;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Interface for task management operations.
|
|
119
|
+
* Provides high-level methods for managing task workflow and state transitions.
|
|
120
|
+
* @public
|
|
121
|
+
*/
|
|
122
|
+
export interface ITaskManager {
|
|
123
|
+
/**
|
|
124
|
+
* Mark a task as finished.
|
|
125
|
+
* Transitions the task to 'done' status.
|
|
126
|
+
* @param taskId - The unique identifier of the task
|
|
127
|
+
* @returns The updated task
|
|
128
|
+
* @throws Error if task is not found
|
|
129
|
+
*/
|
|
130
|
+
finishTask(taskId: string): Promise<TaskFile>;
|
|
131
|
+
/**
|
|
132
|
+
* Start working on a task.
|
|
133
|
+
* Transitions the task to 'in-progress' status.
|
|
134
|
+
* @param taskId - The unique identifier of the task
|
|
135
|
+
* @returns The updated task
|
|
136
|
+
* @throws Error if task is not found, already in progress, or already done
|
|
137
|
+
*/
|
|
138
|
+
startTask(taskId: string): Promise<TaskFile>;
|
|
139
|
+
/**
|
|
140
|
+
* Create a new task.
|
|
141
|
+
* @param options - Options for creating the task
|
|
142
|
+
* @returns The created task information
|
|
143
|
+
*/
|
|
144
|
+
createTask(options: CreateTaskOptions): Promise<CreateTaskResult>;
|
|
145
|
+
/**
|
|
146
|
+
* Validate all tasks in the system.
|
|
147
|
+
* Delegates to the underlying provider's lint implementation.
|
|
148
|
+
* @param fix - If true, attempt to automatically fix validation issues
|
|
149
|
+
* @returns The lint result with any validation issues found
|
|
150
|
+
*/
|
|
151
|
+
lint(fix?: boolean): Promise<LintResult>;
|
|
152
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-manager.types.js","sourceRoot":"","sources":["../src/task-manager.types.ts"],"names":[],"mappings":""}
|