@todu/pi-extensions 0.1.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 +95 -0
- package/dist/domain/habit.d.ts +38 -0
- package/dist/domain/habit.js +1 -0
- package/dist/domain/note.d.ts +21 -0
- package/dist/domain/note.js +1 -0
- package/dist/domain/recurring.d.ts +29 -0
- package/dist/domain/recurring.js +1 -0
- package/dist/domain/task-actions.d.ts +24 -0
- package/dist/domain/task-actions.js +1 -0
- package/dist/domain/task.d.ts +50 -0
- package/dist/domain/task.js +1 -0
- package/dist/extension/current-task-context.d.ts +26 -0
- package/dist/extension/current-task-context.js +140 -0
- package/dist/extension/register-commands.d.ts +114 -0
- package/dist/extension/register-commands.js +1214 -0
- package/dist/extension/register-events.d.ts +3 -0
- package/dist/extension/register-events.js +30 -0
- package/dist/extension/register-tools.d.ts +17 -0
- package/dist/extension/register-tools.js +36 -0
- package/dist/extension/register-ui.d.ts +3 -0
- package/dist/extension/register-ui.js +7 -0
- package/dist/extension/sync-status-context.d.ts +26 -0
- package/dist/extension/sync-status-context.js +162 -0
- package/dist/extension/task-browse-filter-context.d.ts +16 -0
- package/dist/extension/task-browse-filter-context.js +40 -0
- package/dist/flows/browse-tasks.d.ts +7 -0
- package/dist/flows/browse-tasks.js +2 -0
- package/dist/flows/comment-on-task.d.ts +7 -0
- package/dist/flows/comment-on-task.js +2 -0
- package/dist/flows/create-task.d.ts +7 -0
- package/dist/flows/create-task.js +2 -0
- package/dist/flows/pick-current-task.d.ts +7 -0
- package/dist/flows/pick-current-task.js +4 -0
- package/dist/flows/show-task-detail.d.ts +7 -0
- package/dist/flows/show-task-detail.js +2 -0
- package/dist/flows/update-task.d.ts +7 -0
- package/dist/flows/update-task.js +2 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +12 -0
- package/dist/services/habit-service.d.ts +38 -0
- package/dist/services/habit-service.js +1 -0
- package/dist/services/note-service.d.ts +5 -0
- package/dist/services/note-service.js +1 -0
- package/dist/services/project-integration-service.d.ts +109 -0
- package/dist/services/project-integration-service.js +122 -0
- package/dist/services/project-service.d.ts +27 -0
- package/dist/services/project-service.js +8 -0
- package/dist/services/recurring-service.d.ts +37 -0
- package/dist/services/recurring-service.js +1 -0
- package/dist/services/repo-context.d.ts +55 -0
- package/dist/services/repo-context.js +135 -0
- package/dist/services/task-browse-filter-store.d.ts +31 -0
- package/dist/services/task-browse-filter-store.js +47 -0
- package/dist/services/task-service.d.ts +42 -0
- package/dist/services/task-service.js +1 -0
- package/dist/services/task-session-store.d.ts +30 -0
- package/dist/services/task-session-store.js +55 -0
- package/dist/services/todu/daemon-client.d.ts +93 -0
- package/dist/services/todu/daemon-client.js +660 -0
- package/dist/services/todu/daemon-config.d.ts +17 -0
- package/dist/services/todu/daemon-config.js +38 -0
- package/dist/services/todu/daemon-connection.d.ts +61 -0
- package/dist/services/todu/daemon-connection.js +633 -0
- package/dist/services/todu/daemon-events.d.ts +11 -0
- package/dist/services/todu/daemon-events.js +1 -0
- package/dist/services/todu/default-task-service.d.ts +34 -0
- package/dist/services/todu/default-task-service.js +109 -0
- package/dist/services/todu/todu-habit-service.d.ts +24 -0
- package/dist/services/todu/todu-habit-service.js +80 -0
- package/dist/services/todu/todu-note-service.d.ts +20 -0
- package/dist/services/todu/todu-note-service.js +35 -0
- package/dist/services/todu/todu-project-integration-service.d.ts +27 -0
- package/dist/services/todu/todu-project-integration-service.js +45 -0
- package/dist/services/todu/todu-project-service.d.ts +24 -0
- package/dist/services/todu/todu-project-service.js +42 -0
- package/dist/services/todu/todu-recurring-service.d.ts +27 -0
- package/dist/services/todu/todu-recurring-service.js +72 -0
- package/dist/services/todu/todu-task-service.d.ts +23 -0
- package/dist/services/todu/todu-task-service.js +80 -0
- package/dist/tools/habit-mutation-tools.d.ts +170 -0
- package/dist/tools/habit-mutation-tools.js +363 -0
- package/dist/tools/habit-read-tools.d.ts +61 -0
- package/dist/tools/habit-read-tools.js +152 -0
- package/dist/tools/note-read-tools.d.ts +79 -0
- package/dist/tools/note-read-tools.js +148 -0
- package/dist/tools/project-integration-tools.d.ts +92 -0
- package/dist/tools/project-integration-tools.js +344 -0
- package/dist/tools/project-mutation-tools.d.ts +100 -0
- package/dist/tools/project-mutation-tools.js +205 -0
- package/dist/tools/project-read-tools.d.ts +59 -0
- package/dist/tools/project-read-tools.js +131 -0
- package/dist/tools/recurring-mutation-tools.d.ts +130 -0
- package/dist/tools/recurring-mutation-tools.js +317 -0
- package/dist/tools/recurring-read-tools.d.ts +31 -0
- package/dist/tools/recurring-read-tools.js +57 -0
- package/dist/tools/task-mutation-tools.d.ts +159 -0
- package/dist/tools/task-mutation-tools.js +340 -0
- package/dist/tools/task-read-tools.d.ts +91 -0
- package/dist/tools/task-read-tools.js +186 -0
- package/dist/ui/components/habit-table.d.ts +5 -0
- package/dist/ui/components/habit-table.js +34 -0
- package/dist/ui/components/loaders.d.ts +6 -0
- package/dist/ui/components/loaders.js +5 -0
- package/dist/ui/components/task-detail.d.ts +19 -0
- package/dist/ui/components/task-detail.js +74 -0
- package/dist/ui/components/task-list.d.ts +8 -0
- package/dist/ui/components/task-list.js +7 -0
- package/dist/ui/components/task-settings.d.ts +7 -0
- package/dist/ui/components/task-settings.js +12 -0
- package/dist/ui/renderers/task-tool-renderer.d.ts +4 -0
- package/dist/ui/renderers/task-tool-renderer.js +4 -0
- package/dist/ui/widgets/current-task-widget.d.ts +7 -0
- package/dist/ui/widgets/current-task-widget.js +20 -0
- package/dist/ui/widgets/next-actions-widget.d.ts +7 -0
- package/dist/ui/widgets/next-actions-widget.js +5 -0
- package/dist/utils/key-hints.d.ts +6 -0
- package/dist/utils/key-hints.js +2 -0
- package/dist/utils/schedule.d.ts +35 -0
- package/dist/utils/schedule.js +111 -0
- package/dist/utils/task-filters.d.ts +3 -0
- package/dist/utils/task-filters.js +7 -0
- package/dist/utils/task-format.d.ts +4 -0
- package/dist/utils/task-format.js +6 -0
- package/dist/utils/timezone.d.ts +2 -0
- package/dist/utils/timezone.js +9 -0
- package/package.json +79 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { createRepoContextService } from "../repo-context.js";
|
|
2
|
+
import { createToduDaemonClient } from "./daemon-client.js";
|
|
3
|
+
import { createToduDaemonConnection, } from "./daemon-connection.js";
|
|
4
|
+
import { createToduProjectIntegrationService } from "./todu-project-integration-service.js";
|
|
5
|
+
import { createToduProjectService } from "./todu-project-service.js";
|
|
6
|
+
import { createToduHabitService } from "./todu-habit-service.js";
|
|
7
|
+
import { createToduNoteService } from "./todu-note-service.js";
|
|
8
|
+
import { createToduRecurringService } from "./todu-recurring-service.js";
|
|
9
|
+
import { createToduTaskService } from "./todu-task-service.js";
|
|
10
|
+
export const DEFAULT_TODU_INITIAL_CONNECT_TIMEOUT_MS = 2_000;
|
|
11
|
+
const createToduTaskServiceRuntime = (options = {}) => {
|
|
12
|
+
const connection = createToduDaemonConnection(options);
|
|
13
|
+
const client = createToduDaemonClient({ connection });
|
|
14
|
+
const taskService = createToduTaskService({ client });
|
|
15
|
+
const projectService = createToduProjectService({ client });
|
|
16
|
+
const recurringService = createToduRecurringService({ client });
|
|
17
|
+
const habitService = createToduHabitService({ client });
|
|
18
|
+
const noteService = createToduNoteService({ client });
|
|
19
|
+
const projectIntegrationService = createToduProjectIntegrationService({
|
|
20
|
+
client,
|
|
21
|
+
projectService,
|
|
22
|
+
repoContextService: createRepoContextService(),
|
|
23
|
+
});
|
|
24
|
+
const initialConnectTimeoutMs = normalizeTimeout(options.initialConnectTimeoutMs, DEFAULT_TODU_INITIAL_CONNECT_TIMEOUT_MS);
|
|
25
|
+
return {
|
|
26
|
+
connection,
|
|
27
|
+
client,
|
|
28
|
+
taskService,
|
|
29
|
+
projectService,
|
|
30
|
+
recurringService,
|
|
31
|
+
habitService,
|
|
32
|
+
noteService,
|
|
33
|
+
projectIntegrationService,
|
|
34
|
+
ensureConnected: async () => {
|
|
35
|
+
if (connection.getState().status !== "connected") {
|
|
36
|
+
await connectWithinTimeout(connection, initialConnectTimeoutMs);
|
|
37
|
+
}
|
|
38
|
+
return taskService;
|
|
39
|
+
},
|
|
40
|
+
ensureProjectServiceConnected: async () => {
|
|
41
|
+
if (connection.getState().status !== "connected") {
|
|
42
|
+
await connectWithinTimeout(connection, initialConnectTimeoutMs);
|
|
43
|
+
}
|
|
44
|
+
return projectService;
|
|
45
|
+
},
|
|
46
|
+
ensureRecurringServiceConnected: async () => {
|
|
47
|
+
if (connection.getState().status !== "connected") {
|
|
48
|
+
await connectWithinTimeout(connection, initialConnectTimeoutMs);
|
|
49
|
+
}
|
|
50
|
+
return recurringService;
|
|
51
|
+
},
|
|
52
|
+
ensureHabitServiceConnected: async () => {
|
|
53
|
+
if (connection.getState().status !== "connected") {
|
|
54
|
+
await connectWithinTimeout(connection, initialConnectTimeoutMs);
|
|
55
|
+
}
|
|
56
|
+
return habitService;
|
|
57
|
+
},
|
|
58
|
+
ensureNoteServiceConnected: async () => {
|
|
59
|
+
if (connection.getState().status !== "connected") {
|
|
60
|
+
await connectWithinTimeout(connection, initialConnectTimeoutMs);
|
|
61
|
+
}
|
|
62
|
+
return noteService;
|
|
63
|
+
},
|
|
64
|
+
ensureProjectIntegrationServiceConnected: async () => {
|
|
65
|
+
if (connection.getState().status !== "connected") {
|
|
66
|
+
await connectWithinTimeout(connection, initialConnectTimeoutMs);
|
|
67
|
+
}
|
|
68
|
+
return projectIntegrationService;
|
|
69
|
+
},
|
|
70
|
+
disconnect: () => connection.disconnect(),
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
let defaultToduTaskServiceRuntime = null;
|
|
74
|
+
const getDefaultToduTaskServiceRuntime = () => {
|
|
75
|
+
if (!defaultToduTaskServiceRuntime) {
|
|
76
|
+
defaultToduTaskServiceRuntime = createToduTaskServiceRuntime();
|
|
77
|
+
}
|
|
78
|
+
return defaultToduTaskServiceRuntime;
|
|
79
|
+
};
|
|
80
|
+
const resetDefaultToduTaskServiceRuntime = async () => {
|
|
81
|
+
if (defaultToduTaskServiceRuntime) {
|
|
82
|
+
await defaultToduTaskServiceRuntime.disconnect();
|
|
83
|
+
defaultToduTaskServiceRuntime = null;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
const connectWithinTimeout = async (connection, timeoutMs) => {
|
|
87
|
+
let timeoutHandle = null;
|
|
88
|
+
try {
|
|
89
|
+
await Promise.race([
|
|
90
|
+
connection.connect(),
|
|
91
|
+
new Promise((_, reject) => {
|
|
92
|
+
timeoutHandle = setTimeout(() => {
|
|
93
|
+
reject(new Error(`Timed out connecting to the todu daemon after ${timeoutMs}ms`));
|
|
94
|
+
}, timeoutMs);
|
|
95
|
+
}),
|
|
96
|
+
]);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
await connection.disconnect();
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
if (timeoutHandle) {
|
|
104
|
+
clearTimeout(timeoutHandle);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
const normalizeTimeout = (value, fallback) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
|
|
109
|
+
export { connectWithinTimeout, createToduTaskServiceRuntime, getDefaultToduTaskServiceRuntime, resetDefaultToduTaskServiceRuntime, };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { HabitDetail, HabitFilter, HabitSummary, HabitSummaryWithStreak } from "../../domain/habit";
|
|
2
|
+
import type { HabitService } from "../habit-service";
|
|
3
|
+
import { type ToduDaemonClient } from "./daemon-client";
|
|
4
|
+
export declare class ToduHabitServiceError extends Error {
|
|
5
|
+
readonly operation: string;
|
|
6
|
+
readonly causeCode: string;
|
|
7
|
+
readonly details?: Record<string, unknown>;
|
|
8
|
+
constructor(options: {
|
|
9
|
+
operation: string;
|
|
10
|
+
causeCode: string;
|
|
11
|
+
message: string;
|
|
12
|
+
details?: Record<string, unknown>;
|
|
13
|
+
cause?: unknown;
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
export interface ToduHabitServiceDependencies {
|
|
17
|
+
client: ToduDaemonClient;
|
|
18
|
+
}
|
|
19
|
+
declare const createToduHabitService: ({ client }: ToduHabitServiceDependencies) => HabitService;
|
|
20
|
+
declare const listHabitsWithProjectNames: (client: ToduDaemonClient, filter?: HabitFilter) => Promise<HabitSummary[]>;
|
|
21
|
+
declare const hydrateHabitProjectName: (client: ToduDaemonClient, habit: HabitDetail) => Promise<HabitDetail>;
|
|
22
|
+
declare const runHabitServiceOperation: <TResult>(operation: string, action: () => Promise<TResult>) => Promise<TResult>;
|
|
23
|
+
declare const listHabitsWithStreaks: (client: ToduDaemonClient, filter?: HabitFilter) => Promise<HabitSummaryWithStreak[]>;
|
|
24
|
+
export { createToduHabitService, hydrateHabitProjectName, listHabitsWithProjectNames, listHabitsWithStreaks, runHabitServiceOperation, };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { ToduDaemonClientError } from "./daemon-client.js";
|
|
2
|
+
export class ToduHabitServiceError extends Error {
|
|
3
|
+
operation;
|
|
4
|
+
causeCode;
|
|
5
|
+
details;
|
|
6
|
+
constructor(options) {
|
|
7
|
+
super(options.message, options.cause ? { cause: options.cause } : undefined);
|
|
8
|
+
this.name = "ToduHabitServiceError";
|
|
9
|
+
this.operation = options.operation;
|
|
10
|
+
this.causeCode = options.causeCode;
|
|
11
|
+
this.details = options.details;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const createToduHabitService = ({ client }) => ({
|
|
15
|
+
listHabits: (filter) => runHabitServiceOperation("listHabits", () => listHabitsWithProjectNames(client, filter)),
|
|
16
|
+
getHabit: (habitId) => runHabitServiceOperation("getHabit", async () => {
|
|
17
|
+
const habit = await client.getHabit(habitId);
|
|
18
|
+
if (!habit) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return hydrateHabitProjectName(client, habit);
|
|
22
|
+
}),
|
|
23
|
+
createHabit: (input) => runHabitServiceOperation("createHabit", async () => {
|
|
24
|
+
const habit = await client.createHabit(input);
|
|
25
|
+
return hydrateHabitProjectName(client, habit);
|
|
26
|
+
}),
|
|
27
|
+
updateHabit: (input) => runHabitServiceOperation("updateHabit", async () => {
|
|
28
|
+
const habit = await client.updateHabit(input);
|
|
29
|
+
return hydrateHabitProjectName(client, habit);
|
|
30
|
+
}),
|
|
31
|
+
listHabitsWithStreaks: (filter) => runHabitServiceOperation("listHabitsWithStreaks", () => listHabitsWithStreaks(client, filter)),
|
|
32
|
+
getHabitStreak: (habitId) => runHabitServiceOperation("getHabitStreak", () => client.getHabitStreak(habitId)),
|
|
33
|
+
checkHabit: (habitId) => runHabitServiceOperation("checkHabit", () => client.checkHabit(habitId)),
|
|
34
|
+
deleteHabit: (habitId) => runHabitServiceOperation("deleteHabit", () => client.deleteHabit(habitId)),
|
|
35
|
+
addHabitNote: (input) => runHabitServiceOperation("addHabitNote", () => client.addHabitNote(input)),
|
|
36
|
+
});
|
|
37
|
+
const listHabitsWithProjectNames = async (client, filter) => {
|
|
38
|
+
const [habits, projects] = await Promise.all([client.listHabits(filter), client.listProjects()]);
|
|
39
|
+
const projectNames = new Map(projects.map((project) => [project.id, project.name]));
|
|
40
|
+
return habits.map((habit) => ({
|
|
41
|
+
...habit,
|
|
42
|
+
projectName: projectNames.get(habit.projectId) ?? null,
|
|
43
|
+
}));
|
|
44
|
+
};
|
|
45
|
+
const hydrateHabitProjectName = async (client, habit) => {
|
|
46
|
+
const project = await client.getProject(habit.projectId);
|
|
47
|
+
return {
|
|
48
|
+
...habit,
|
|
49
|
+
projectName: project?.name ?? null,
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
const runHabitServiceOperation = async (operation, action) => {
|
|
53
|
+
try {
|
|
54
|
+
return await action();
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (error instanceof ToduDaemonClientError) {
|
|
58
|
+
throw new ToduHabitServiceError({
|
|
59
|
+
operation,
|
|
60
|
+
causeCode: error.code,
|
|
61
|
+
message: `${operation} failed: ${error.message}`,
|
|
62
|
+
details: error.details,
|
|
63
|
+
cause: error,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const listHabitsWithStreaks = async (client, filter) => {
|
|
70
|
+
const habits = await listHabitsWithProjectNames(client, filter);
|
|
71
|
+
const streakResults = await Promise.allSettled(habits.map((habit) => client.getHabitStreak(habit.id)));
|
|
72
|
+
return habits.map((habit, index) => {
|
|
73
|
+
const streakResult = streakResults[index];
|
|
74
|
+
return {
|
|
75
|
+
...habit,
|
|
76
|
+
streak: streakResult?.status === "fulfilled" ? streakResult.value : null,
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
export { createToduHabitService, hydrateHabitProjectName, listHabitsWithProjectNames, listHabitsWithStreaks, runHabitServiceOperation, };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { NoteService } from "../note-service";
|
|
2
|
+
import { type ToduDaemonClient } from "./daemon-client";
|
|
3
|
+
export declare class ToduNoteServiceError extends Error {
|
|
4
|
+
readonly operation: string;
|
|
5
|
+
readonly causeCode: string;
|
|
6
|
+
readonly details?: Record<string, unknown>;
|
|
7
|
+
constructor(options: {
|
|
8
|
+
operation: string;
|
|
9
|
+
causeCode: string;
|
|
10
|
+
message: string;
|
|
11
|
+
details?: Record<string, unknown>;
|
|
12
|
+
cause?: unknown;
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
export interface ToduNoteServiceDependencies {
|
|
16
|
+
client: ToduDaemonClient;
|
|
17
|
+
}
|
|
18
|
+
declare const createToduNoteService: ({ client }: ToduNoteServiceDependencies) => NoteService;
|
|
19
|
+
declare const runNoteServiceOperation: <TResult>(operation: string, action: () => Promise<TResult>) => Promise<TResult>;
|
|
20
|
+
export { createToduNoteService, runNoteServiceOperation };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ToduDaemonClientError } from "./daemon-client.js";
|
|
2
|
+
export class ToduNoteServiceError extends Error {
|
|
3
|
+
operation;
|
|
4
|
+
causeCode;
|
|
5
|
+
details;
|
|
6
|
+
constructor(options) {
|
|
7
|
+
super(options.message, options.cause ? { cause: options.cause } : undefined);
|
|
8
|
+
this.name = "ToduNoteServiceError";
|
|
9
|
+
this.operation = options.operation;
|
|
10
|
+
this.causeCode = options.causeCode;
|
|
11
|
+
this.details = options.details;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const createToduNoteService = ({ client }) => ({
|
|
15
|
+
listNotes: (filter) => runNoteServiceOperation("listNotes", () => client.listNotes(filter)),
|
|
16
|
+
getNote: (noteId) => runNoteServiceOperation("getNote", () => client.getNote(noteId)),
|
|
17
|
+
});
|
|
18
|
+
const runNoteServiceOperation = async (operation, action) => {
|
|
19
|
+
try {
|
|
20
|
+
return await action();
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
if (error instanceof ToduDaemonClientError) {
|
|
24
|
+
throw new ToduNoteServiceError({
|
|
25
|
+
operation,
|
|
26
|
+
causeCode: error.code,
|
|
27
|
+
message: `${operation} failed: ${error.message}`,
|
|
28
|
+
details: error.details,
|
|
29
|
+
cause: error,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
export { createToduNoteService, runNoteServiceOperation };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ProjectIntegrationGateway, ProjectIntegrationService } from "../project-integration-service";
|
|
2
|
+
import type { ProjectService } from "../project-service";
|
|
3
|
+
import type { RepoContextService } from "../repo-context";
|
|
4
|
+
import { type ToduDaemonClient } from "./daemon-client";
|
|
5
|
+
export declare class ToduProjectIntegrationServiceError extends Error {
|
|
6
|
+
readonly operation: string;
|
|
7
|
+
readonly causeCode: string;
|
|
8
|
+
readonly details?: Record<string, unknown>;
|
|
9
|
+
constructor(options: {
|
|
10
|
+
operation: string;
|
|
11
|
+
causeCode: string;
|
|
12
|
+
message: string;
|
|
13
|
+
details?: Record<string, unknown>;
|
|
14
|
+
cause?: unknown;
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
export interface ToduProjectIntegrationGatewayDependencies {
|
|
18
|
+
client: ToduDaemonClient;
|
|
19
|
+
}
|
|
20
|
+
declare const createToduProjectIntegrationGateway: ({ client, }: ToduProjectIntegrationGatewayDependencies) => ProjectIntegrationGateway;
|
|
21
|
+
declare const createToduProjectIntegrationService: ({ client, projectService, repoContextService, }: {
|
|
22
|
+
client: ToduDaemonClient;
|
|
23
|
+
projectService: ProjectService;
|
|
24
|
+
repoContextService: RepoContextService;
|
|
25
|
+
}) => ProjectIntegrationService;
|
|
26
|
+
declare const runProjectIntegrationServiceOperation: <TResult>(operation: string, action: () => Promise<TResult>) => Promise<TResult>;
|
|
27
|
+
export { createToduProjectIntegrationGateway, createToduProjectIntegrationService, runProjectIntegrationServiceOperation, };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { createProjectIntegrationService } from "../project-integration-service.js";
|
|
2
|
+
import { ToduDaemonClientError } from "./daemon-client.js";
|
|
3
|
+
export class ToduProjectIntegrationServiceError extends Error {
|
|
4
|
+
operation;
|
|
5
|
+
causeCode;
|
|
6
|
+
details;
|
|
7
|
+
constructor(options) {
|
|
8
|
+
super(options.message, options.cause ? { cause: options.cause } : undefined);
|
|
9
|
+
this.name = "ToduProjectIntegrationServiceError";
|
|
10
|
+
this.operation = options.operation;
|
|
11
|
+
this.causeCode = options.causeCode;
|
|
12
|
+
this.details = options.details;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const createToduProjectIntegrationGateway = ({ client, }) => ({
|
|
16
|
+
listIntegrationBindings: (filter) => client.listIntegrationBindings(filter),
|
|
17
|
+
createIntegrationBinding: (input) => client.createIntegrationBinding(input),
|
|
18
|
+
});
|
|
19
|
+
const createToduProjectIntegrationService = ({ client, projectService, repoContextService, }) => {
|
|
20
|
+
const gateway = createToduProjectIntegrationGateway({ client });
|
|
21
|
+
const service = createProjectIntegrationService({ projectService, repoContextService, gateway });
|
|
22
|
+
return {
|
|
23
|
+
listIntegrationBindings: (filter) => runProjectIntegrationServiceOperation("listIntegrationBindings", () => service.listIntegrationBindings(filter)),
|
|
24
|
+
checkRepositoryBinding: (input) => runProjectIntegrationServiceOperation("checkRepositoryBinding", () => service.checkRepositoryBinding(input)),
|
|
25
|
+
registerRepositoryProject: (input) => runProjectIntegrationServiceOperation("registerRepositoryProject", () => service.registerRepositoryProject(input)),
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
const runProjectIntegrationServiceOperation = async (operation, action) => {
|
|
29
|
+
try {
|
|
30
|
+
return await action();
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (error instanceof ToduDaemonClientError) {
|
|
34
|
+
throw new ToduProjectIntegrationServiceError({
|
|
35
|
+
operation,
|
|
36
|
+
causeCode: error.code,
|
|
37
|
+
message: `${operation} failed: ${error.message}`,
|
|
38
|
+
details: error.details,
|
|
39
|
+
cause: error,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
export { createToduProjectIntegrationGateway, createToduProjectIntegrationService, runProjectIntegrationServiceOperation, };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { CreateProjectInput, DeleteProjectResult, ProjectService, UpdateProjectInput } from "../project-service";
|
|
2
|
+
import { type ToduDaemonClient } from "./daemon-client";
|
|
3
|
+
export declare class ToduProjectServiceError extends Error {
|
|
4
|
+
readonly operation: string;
|
|
5
|
+
readonly causeCode: string;
|
|
6
|
+
readonly details?: Record<string, unknown>;
|
|
7
|
+
constructor(options: {
|
|
8
|
+
operation: string;
|
|
9
|
+
causeCode: string;
|
|
10
|
+
message: string;
|
|
11
|
+
details?: Record<string, unknown>;
|
|
12
|
+
cause?: unknown;
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
export interface ToduProjectServiceDependencies {
|
|
16
|
+
client: ToduDaemonClient;
|
|
17
|
+
}
|
|
18
|
+
declare const createToduProjectService: ({ client }: ToduProjectServiceDependencies) => ProjectService;
|
|
19
|
+
declare const runProjectServiceOperation: <TProjectResult>(operation: string, action: () => Promise<TProjectResult>) => Promise<TProjectResult>;
|
|
20
|
+
declare const listProjects: (projectService: ProjectService) => Promise<import("../../domain/task").ProjectSummary[]>;
|
|
21
|
+
declare const createProject: (projectService: ProjectService, input: CreateProjectInput) => Promise<import("../../domain/task").ProjectSummary>;
|
|
22
|
+
declare const updateProject: (projectService: ProjectService, input: UpdateProjectInput) => Promise<import("../../domain/task").ProjectSummary>;
|
|
23
|
+
declare const deleteProject: (projectService: ProjectService, projectId: string) => Promise<DeleteProjectResult>;
|
|
24
|
+
export { createProject, createToduProjectService, deleteProject, listProjects, runProjectServiceOperation, updateProject, };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ToduDaemonClientError } from "./daemon-client.js";
|
|
2
|
+
export class ToduProjectServiceError extends Error {
|
|
3
|
+
operation;
|
|
4
|
+
causeCode;
|
|
5
|
+
details;
|
|
6
|
+
constructor(options) {
|
|
7
|
+
super(options.message, options.cause ? { cause: options.cause } : undefined);
|
|
8
|
+
this.name = "ToduProjectServiceError";
|
|
9
|
+
this.operation = options.operation;
|
|
10
|
+
this.causeCode = options.causeCode;
|
|
11
|
+
this.details = options.details;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const createToduProjectService = ({ client }) => ({
|
|
15
|
+
listProjects: () => runProjectServiceOperation("listProjects", () => client.listProjects()),
|
|
16
|
+
getProject: (projectId) => runProjectServiceOperation("getProject", () => client.getProject(projectId)),
|
|
17
|
+
createProject: (input) => runProjectServiceOperation("createProject", () => client.createProject(input)),
|
|
18
|
+
updateProject: (input) => runProjectServiceOperation("updateProject", () => client.updateProject(input)),
|
|
19
|
+
deleteProject: (projectId) => runProjectServiceOperation("deleteProject", () => client.deleteProject(projectId)),
|
|
20
|
+
});
|
|
21
|
+
const runProjectServiceOperation = async (operation, action) => {
|
|
22
|
+
try {
|
|
23
|
+
return await action();
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
if (error instanceof ToduDaemonClientError) {
|
|
27
|
+
throw new ToduProjectServiceError({
|
|
28
|
+
operation,
|
|
29
|
+
causeCode: error.code,
|
|
30
|
+
message: `${operation} failed: ${error.message}`,
|
|
31
|
+
details: error.details,
|
|
32
|
+
cause: error,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
const listProjects = async (projectService) => projectService.listProjects();
|
|
39
|
+
const createProject = async (projectService, input) => projectService.createProject(input);
|
|
40
|
+
const updateProject = async (projectService, input) => projectService.updateProject(input);
|
|
41
|
+
const deleteProject = async (projectService, projectId) => projectService.deleteProject(projectId);
|
|
42
|
+
export { createProject, createToduProjectService, deleteProject, listProjects, runProjectServiceOperation, updateProject, };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { RecurringFilter, RecurringTemplateDetail, RecurringTemplateSummary } from "../../domain/recurring";
|
|
2
|
+
import type { RecurringService, CreateRecurringInput, DeleteRecurringResult, UpdateRecurringInput } from "../recurring-service";
|
|
3
|
+
import { type ToduDaemonClient } from "./daemon-client";
|
|
4
|
+
export declare class ToduRecurringServiceError extends Error {
|
|
5
|
+
readonly operation: string;
|
|
6
|
+
readonly causeCode: string;
|
|
7
|
+
readonly details?: Record<string, unknown>;
|
|
8
|
+
constructor(options: {
|
|
9
|
+
operation: string;
|
|
10
|
+
causeCode: string;
|
|
11
|
+
message: string;
|
|
12
|
+
details?: Record<string, unknown>;
|
|
13
|
+
cause?: unknown;
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
export interface ToduRecurringServiceDependencies {
|
|
17
|
+
client: ToduDaemonClient;
|
|
18
|
+
}
|
|
19
|
+
declare const createToduRecurringService: ({ client, }: ToduRecurringServiceDependencies) => RecurringService;
|
|
20
|
+
declare const listRecurringWithProjectNames: (client: ToduDaemonClient, filter?: RecurringFilter) => Promise<RecurringTemplateSummary[]>;
|
|
21
|
+
declare const hydrateRecurringProjectName: (client: ToduDaemonClient, template: RecurringTemplateDetail) => Promise<RecurringTemplateDetail>;
|
|
22
|
+
declare const runRecurringServiceOperation: <TResult>(operation: string, action: () => Promise<TResult>) => Promise<TResult>;
|
|
23
|
+
declare const listRecurring: (recurringService: RecurringService, filter?: RecurringFilter) => Promise<RecurringTemplateSummary[]>;
|
|
24
|
+
declare const createRecurring: (recurringService: RecurringService, input: CreateRecurringInput) => Promise<RecurringTemplateDetail>;
|
|
25
|
+
declare const updateRecurring: (recurringService: RecurringService, input: UpdateRecurringInput) => Promise<RecurringTemplateDetail>;
|
|
26
|
+
declare const deleteRecurring: (recurringService: RecurringService, recurringId: string) => Promise<DeleteRecurringResult>;
|
|
27
|
+
export { createRecurring, createToduRecurringService, deleteRecurring, hydrateRecurringProjectName, listRecurring, listRecurringWithProjectNames, runRecurringServiceOperation, updateRecurring, };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { ToduDaemonClientError } from "./daemon-client.js";
|
|
2
|
+
export class ToduRecurringServiceError extends Error {
|
|
3
|
+
operation;
|
|
4
|
+
causeCode;
|
|
5
|
+
details;
|
|
6
|
+
constructor(options) {
|
|
7
|
+
super(options.message, options.cause ? { cause: options.cause } : undefined);
|
|
8
|
+
this.name = "ToduRecurringServiceError";
|
|
9
|
+
this.operation = options.operation;
|
|
10
|
+
this.causeCode = options.causeCode;
|
|
11
|
+
this.details = options.details;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const createToduRecurringService = ({ client, }) => ({
|
|
15
|
+
listRecurring: (filter) => runRecurringServiceOperation("listRecurring", () => listRecurringWithProjectNames(client, filter)),
|
|
16
|
+
getRecurring: (recurringId) => runRecurringServiceOperation("getRecurring", async () => {
|
|
17
|
+
const template = await client.getRecurring(recurringId);
|
|
18
|
+
if (!template) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return hydrateRecurringProjectName(client, template);
|
|
22
|
+
}),
|
|
23
|
+
createRecurring: (input) => runRecurringServiceOperation("createRecurring", async () => {
|
|
24
|
+
const template = await client.createRecurring(input);
|
|
25
|
+
return hydrateRecurringProjectName(client, template);
|
|
26
|
+
}),
|
|
27
|
+
updateRecurring: (input) => runRecurringServiceOperation("updateRecurring", async () => {
|
|
28
|
+
const template = await client.updateRecurring(input);
|
|
29
|
+
return hydrateRecurringProjectName(client, template);
|
|
30
|
+
}),
|
|
31
|
+
deleteRecurring: (recurringId) => runRecurringServiceOperation("deleteRecurring", () => client.deleteRecurring(recurringId)),
|
|
32
|
+
});
|
|
33
|
+
const listRecurringWithProjectNames = async (client, filter) => {
|
|
34
|
+
const [templates, projects] = await Promise.all([
|
|
35
|
+
client.listRecurring(filter),
|
|
36
|
+
client.listProjects(),
|
|
37
|
+
]);
|
|
38
|
+
const projectNames = new Map(projects.map((project) => [project.id, project.name]));
|
|
39
|
+
return templates.map((template) => ({
|
|
40
|
+
...template,
|
|
41
|
+
projectName: projectNames.get(template.projectId) ?? null,
|
|
42
|
+
}));
|
|
43
|
+
};
|
|
44
|
+
const hydrateRecurringProjectName = async (client, template) => {
|
|
45
|
+
const project = await client.getProject(template.projectId);
|
|
46
|
+
return {
|
|
47
|
+
...template,
|
|
48
|
+
projectName: project?.name ?? null,
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
const runRecurringServiceOperation = async (operation, action) => {
|
|
52
|
+
try {
|
|
53
|
+
return await action();
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (error instanceof ToduDaemonClientError) {
|
|
57
|
+
throw new ToduRecurringServiceError({
|
|
58
|
+
operation,
|
|
59
|
+
causeCode: error.code,
|
|
60
|
+
message: `${operation} failed: ${error.message}`,
|
|
61
|
+
details: error.details,
|
|
62
|
+
cause: error,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
const listRecurring = async (recurringService, filter) => recurringService.listRecurring(filter);
|
|
69
|
+
const createRecurring = async (recurringService, input) => recurringService.createRecurring(input);
|
|
70
|
+
const updateRecurring = async (recurringService, input) => recurringService.updateRecurring(input);
|
|
71
|
+
const deleteRecurring = async (recurringService, recurringId) => recurringService.deleteRecurring(recurringId);
|
|
72
|
+
export { createRecurring, createToduRecurringService, deleteRecurring, hydrateRecurringProjectName, listRecurring, listRecurringWithProjectNames, runRecurringServiceOperation, updateRecurring, };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { TaskDetail, TaskFilter, TaskSummary } from "../../domain/task";
|
|
2
|
+
import type { TaskService } from "../task-service";
|
|
3
|
+
import { type ToduDaemonClient } from "./daemon-client";
|
|
4
|
+
export declare class ToduTaskServiceError extends Error {
|
|
5
|
+
readonly operation: string;
|
|
6
|
+
readonly causeCode: string;
|
|
7
|
+
readonly details?: Record<string, unknown>;
|
|
8
|
+
constructor(options: {
|
|
9
|
+
operation: string;
|
|
10
|
+
causeCode: string;
|
|
11
|
+
message: string;
|
|
12
|
+
details?: Record<string, unknown>;
|
|
13
|
+
cause?: unknown;
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
export interface ToduTaskServiceDependencies {
|
|
17
|
+
client: ToduDaemonClient;
|
|
18
|
+
}
|
|
19
|
+
declare const createToduTaskService: ({ client }: ToduTaskServiceDependencies) => TaskService;
|
|
20
|
+
declare const listTasksWithProjectNames: (client: ToduDaemonClient, filter?: TaskFilter) => Promise<TaskSummary[]>;
|
|
21
|
+
declare const hydrateTaskDetailProjectName: (client: ToduDaemonClient, task: TaskDetail) => Promise<TaskDetail>;
|
|
22
|
+
declare const runTaskServiceOperation: <T>(operation: string, action: () => Promise<T>) => Promise<T>;
|
|
23
|
+
export { createToduTaskService, hydrateTaskDetailProjectName, listTasksWithProjectNames, runTaskServiceOperation, };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { ToduDaemonClientError } from "./daemon-client.js";
|
|
2
|
+
export class ToduTaskServiceError extends Error {
|
|
3
|
+
operation;
|
|
4
|
+
causeCode;
|
|
5
|
+
details;
|
|
6
|
+
constructor(options) {
|
|
7
|
+
super(options.message, options.cause ? { cause: options.cause } : undefined);
|
|
8
|
+
this.name = "ToduTaskServiceError";
|
|
9
|
+
this.operation = options.operation;
|
|
10
|
+
this.causeCode = options.causeCode;
|
|
11
|
+
this.details = options.details;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const createToduTaskService = ({ client }) => ({
|
|
15
|
+
listTasks: (filter) => runTaskServiceOperation("listTasks", () => listTasksWithProjectNames(client, filter)),
|
|
16
|
+
getTask: (taskId) => runTaskServiceOperation("getTask", async () => {
|
|
17
|
+
const task = await client.getTask(taskId);
|
|
18
|
+
if (!task) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return hydrateTaskDetailProjectName(client, task);
|
|
22
|
+
}),
|
|
23
|
+
createTask: (input) => runTaskServiceOperation("createTask", async () => {
|
|
24
|
+
const task = await client.createTask(input);
|
|
25
|
+
return hydrateTaskDetailProjectName(client, task);
|
|
26
|
+
}),
|
|
27
|
+
updateTask: (input) => runTaskServiceOperation("updateTask", async () => {
|
|
28
|
+
const task = await client.updateTask(input);
|
|
29
|
+
return hydrateTaskDetailProjectName(client, task);
|
|
30
|
+
}),
|
|
31
|
+
addTaskComment: (input) => runTaskServiceOperation("addTaskComment", () => client.addTaskComment(input)),
|
|
32
|
+
deleteTask: (taskId) => runTaskServiceOperation("deleteTask", () => client.deleteTask(taskId)),
|
|
33
|
+
moveTask: (input) => runTaskServiceOperation("moveTask", async () => {
|
|
34
|
+
const result = await client.moveTask(input);
|
|
35
|
+
const targetTask = await hydrateTaskDetailProjectName(client, result.targetTask);
|
|
36
|
+
return { ...result, targetTask };
|
|
37
|
+
}),
|
|
38
|
+
listProjects: () => runTaskServiceOperation("listProjects", () => client.listProjects()),
|
|
39
|
+
getProject: (projectId) => runTaskServiceOperation("getProject", () => client.getProject(projectId)),
|
|
40
|
+
listTaskComments: (taskId) => runTaskServiceOperation("listTaskComments", () => client.listTaskComments(taskId)),
|
|
41
|
+
});
|
|
42
|
+
const listTasksWithProjectNames = async (client, filter) => {
|
|
43
|
+
const [tasks, projects] = await Promise.all([client.listTasks(filter), client.listProjects()]);
|
|
44
|
+
const projectNames = new Map(projects.map((project) => [project.id, project.name]));
|
|
45
|
+
return tasks.map((task) => ({
|
|
46
|
+
...task,
|
|
47
|
+
projectName: task.projectId ? (projectNames.get(task.projectId) ?? null) : null,
|
|
48
|
+
}));
|
|
49
|
+
};
|
|
50
|
+
const hydrateTaskDetailProjectName = async (client, task) => {
|
|
51
|
+
if (!task.projectId) {
|
|
52
|
+
return {
|
|
53
|
+
...task,
|
|
54
|
+
projectName: null,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const project = await client.getProject(task.projectId);
|
|
58
|
+
return {
|
|
59
|
+
...task,
|
|
60
|
+
projectName: project?.name ?? null,
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
const runTaskServiceOperation = async (operation, action) => {
|
|
64
|
+
try {
|
|
65
|
+
return await action();
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
if (error instanceof ToduDaemonClientError) {
|
|
69
|
+
throw new ToduTaskServiceError({
|
|
70
|
+
operation,
|
|
71
|
+
causeCode: error.code,
|
|
72
|
+
message: `${operation} failed: ${error.message}`,
|
|
73
|
+
details: error.details,
|
|
74
|
+
cause: error,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
export { createToduTaskService, hydrateTaskDetailProjectName, listTasksWithProjectNames, runTaskServiceOperation, };
|