@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,152 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
2
|
+
const HabitListParams = Type.Object({});
|
|
3
|
+
const HabitShowParams = Type.Object({
|
|
4
|
+
habitId: Type.String({ description: "Habit ID" }),
|
|
5
|
+
});
|
|
6
|
+
const createHabitListToolDefinition = ({ getHabitService }) => ({
|
|
7
|
+
name: "habit_list",
|
|
8
|
+
label: "Habit List",
|
|
9
|
+
description: "List habits.",
|
|
10
|
+
promptSnippet: "List habits through the native habit service.",
|
|
11
|
+
promptGuidelines: [
|
|
12
|
+
"Use this tool for backend habit lookups in normal chat.",
|
|
13
|
+
"Keep habit_list unfiltered in the first wave unless the task explicitly widens scope.",
|
|
14
|
+
],
|
|
15
|
+
parameters: HabitListParams,
|
|
16
|
+
async execute(_toolCallId, _params) {
|
|
17
|
+
try {
|
|
18
|
+
const habitService = await getHabitService();
|
|
19
|
+
const habits = await habitService.listHabitsWithStreaks();
|
|
20
|
+
const details = {
|
|
21
|
+
kind: "habit_list",
|
|
22
|
+
habits,
|
|
23
|
+
total: habits.length,
|
|
24
|
+
empty: habits.length === 0,
|
|
25
|
+
};
|
|
26
|
+
return {
|
|
27
|
+
content: [{ type: "text", text: formatHabitListContent(details) }],
|
|
28
|
+
details,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
throw new Error(formatToolError(error, "habit_list failed"), { cause: error });
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
const createHabitShowToolDefinition = ({ getHabitService }) => ({
|
|
37
|
+
name: "habit_show",
|
|
38
|
+
label: "Habit Show",
|
|
39
|
+
description: "Show habit details, including description, schedule, and streak.",
|
|
40
|
+
promptSnippet: "Show details for a specific habit by habit ID.",
|
|
41
|
+
promptGuidelines: [
|
|
42
|
+
"Use this tool when the user asks for details about a known habit ID.",
|
|
43
|
+
"If the habit is missing, report the explicit not-found result instead of guessing.",
|
|
44
|
+
],
|
|
45
|
+
parameters: HabitShowParams,
|
|
46
|
+
async execute(_toolCallId, params) {
|
|
47
|
+
try {
|
|
48
|
+
const habitService = await getHabitService();
|
|
49
|
+
const habit = await habitService.getHabit(params.habitId);
|
|
50
|
+
if (!habit) {
|
|
51
|
+
const details = {
|
|
52
|
+
kind: "habit_show",
|
|
53
|
+
habitId: params.habitId,
|
|
54
|
+
found: false,
|
|
55
|
+
};
|
|
56
|
+
return {
|
|
57
|
+
content: [{ type: "text", text: `Habit not found: ${params.habitId}` }],
|
|
58
|
+
details,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const streak = await safeGetStreak(habitService, params.habitId);
|
|
62
|
+
const details = {
|
|
63
|
+
kind: "habit_show",
|
|
64
|
+
habitId: params.habitId,
|
|
65
|
+
found: true,
|
|
66
|
+
habit,
|
|
67
|
+
streak: streak ?? undefined,
|
|
68
|
+
};
|
|
69
|
+
return {
|
|
70
|
+
content: [{ type: "text", text: formatHabitShowContent(habit, streak) }],
|
|
71
|
+
details,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
throw new Error(formatToolError(error, "habit_show failed"), { cause: error });
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
const registerHabitReadTools = (pi, dependencies) => {
|
|
80
|
+
pi.registerTool(createHabitListToolDefinition(dependencies));
|
|
81
|
+
pi.registerTool(createHabitShowToolDefinition(dependencies));
|
|
82
|
+
};
|
|
83
|
+
const safeGetStreak = async (habitService, habitId) => {
|
|
84
|
+
try {
|
|
85
|
+
return await habitService.getHabitStreak(habitId);
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
const formatHabitListContent = (details) => {
|
|
92
|
+
if (details.empty) {
|
|
93
|
+
return "No habits found.";
|
|
94
|
+
}
|
|
95
|
+
const lines = [`Habits (${details.total}):`];
|
|
96
|
+
for (const habit of details.habits) {
|
|
97
|
+
lines.push(`- ${formatHabitSummaryLine(habit)}`);
|
|
98
|
+
}
|
|
99
|
+
return lines.join("\n");
|
|
100
|
+
};
|
|
101
|
+
const formatHabitSummaryLine = (habit) => {
|
|
102
|
+
const projectLabel = habit.projectName ?? habit.projectId;
|
|
103
|
+
const status = habit.paused ? "paused" : "active";
|
|
104
|
+
const streakLabel = formatStreakLabel(habit.streak);
|
|
105
|
+
const todayLabel = formatTodayLabel(habit.streak);
|
|
106
|
+
return `${habit.id} • ${habit.title} • ${status} • ${projectLabel} • streak: ${streakLabel} • today: ${todayLabel}`;
|
|
107
|
+
};
|
|
108
|
+
const formatStreakLabel = (streak) => {
|
|
109
|
+
if (!streak) {
|
|
110
|
+
return "?";
|
|
111
|
+
}
|
|
112
|
+
return streak.current > 0 ? `🔥 ${streak.current}` : "0";
|
|
113
|
+
};
|
|
114
|
+
const formatTodayLabel = (streak) => {
|
|
115
|
+
if (!streak) {
|
|
116
|
+
return "?";
|
|
117
|
+
}
|
|
118
|
+
return streak.completedToday ? "✅" : "—";
|
|
119
|
+
};
|
|
120
|
+
const formatHabitShowContent = (habit, streak) => {
|
|
121
|
+
const status = habit.paused ? "paused" : "active";
|
|
122
|
+
const projectLabel = habit.projectName ?? habit.projectId;
|
|
123
|
+
const streakLabel = streak
|
|
124
|
+
? `${streak.current} current, ${streak.longest} longest, ${streak.totalCheckins} total`
|
|
125
|
+
: "unknown";
|
|
126
|
+
const todayLabel = streak ? (streak.completedToday ? "✅" : "—") : "?";
|
|
127
|
+
const lines = [
|
|
128
|
+
`Habit ${habit.id}: ${habit.title}`,
|
|
129
|
+
"",
|
|
130
|
+
`Status: ${status}`,
|
|
131
|
+
`Project: ${projectLabel}`,
|
|
132
|
+
`Schedule: ${habit.schedule}`,
|
|
133
|
+
`Timezone: ${habit.timezone}`,
|
|
134
|
+
`Start: ${habit.startDate}`,
|
|
135
|
+
`End: ${habit.endDate ?? "none"}`,
|
|
136
|
+
`Next due: ${habit.nextDue}`,
|
|
137
|
+
"",
|
|
138
|
+
"Description:",
|
|
139
|
+
habit.description?.trim().length ? habit.description : "(none)",
|
|
140
|
+
"",
|
|
141
|
+
`Streak: ${streakLabel}`,
|
|
142
|
+
`Today: ${todayLabel}`,
|
|
143
|
+
];
|
|
144
|
+
return lines.join("\n");
|
|
145
|
+
};
|
|
146
|
+
const formatToolError = (error, prefix) => {
|
|
147
|
+
if (error instanceof Error && error.message.trim().length > 0) {
|
|
148
|
+
return `${prefix}: ${error.message}`;
|
|
149
|
+
}
|
|
150
|
+
return prefix;
|
|
151
|
+
};
|
|
152
|
+
export { createHabitListToolDefinition, createHabitShowToolDefinition, formatHabitListContent, formatHabitShowContent, formatStreakLabel, formatTodayLabel, registerHabitReadTools, };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
2
|
+
import type { NoteEntityType, NoteFilter, NoteSummary } from "../domain/note";
|
|
3
|
+
import type { NoteService } from "../services/note-service";
|
|
4
|
+
interface NoteListToolParams {
|
|
5
|
+
entityType?: NoteEntityType;
|
|
6
|
+
entityId?: string;
|
|
7
|
+
tag?: string;
|
|
8
|
+
author?: string;
|
|
9
|
+
from?: string;
|
|
10
|
+
to?: string;
|
|
11
|
+
journal?: boolean;
|
|
12
|
+
timezone?: string;
|
|
13
|
+
}
|
|
14
|
+
interface NoteListToolDetails {
|
|
15
|
+
kind: "note_list";
|
|
16
|
+
filter: NoteFilter;
|
|
17
|
+
notes: NoteSummary[];
|
|
18
|
+
total: number;
|
|
19
|
+
empty: boolean;
|
|
20
|
+
}
|
|
21
|
+
interface NoteShowToolParams {
|
|
22
|
+
noteId: string;
|
|
23
|
+
}
|
|
24
|
+
interface NoteShowToolDetails {
|
|
25
|
+
kind: "note_show";
|
|
26
|
+
noteId: string;
|
|
27
|
+
found: boolean;
|
|
28
|
+
note?: NoteSummary;
|
|
29
|
+
}
|
|
30
|
+
interface NoteReadToolDependencies {
|
|
31
|
+
getNoteService: () => Promise<NoteService>;
|
|
32
|
+
}
|
|
33
|
+
declare const createNoteListToolDefinition: ({ getNoteService }: NoteReadToolDependencies) => {
|
|
34
|
+
name: string;
|
|
35
|
+
label: string;
|
|
36
|
+
description: string;
|
|
37
|
+
promptSnippet: string;
|
|
38
|
+
promptGuidelines: string[];
|
|
39
|
+
parameters: import("@sinclair/typebox").TObject<{
|
|
40
|
+
entityType: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnsafe<"task" | "project" | "habit">>;
|
|
41
|
+
entityId: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
42
|
+
tag: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
43
|
+
author: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
44
|
+
from: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
45
|
+
to: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
46
|
+
journal: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
47
|
+
timezone: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
48
|
+
}>;
|
|
49
|
+
execute(_toolCallId: string, params: NoteListToolParams): Promise<{
|
|
50
|
+
content: {
|
|
51
|
+
type: "text";
|
|
52
|
+
text: string;
|
|
53
|
+
}[];
|
|
54
|
+
details: NoteListToolDetails;
|
|
55
|
+
}>;
|
|
56
|
+
};
|
|
57
|
+
declare const createNoteShowToolDefinition: ({ getNoteService }: NoteReadToolDependencies) => {
|
|
58
|
+
name: string;
|
|
59
|
+
label: string;
|
|
60
|
+
description: string;
|
|
61
|
+
promptSnippet: string;
|
|
62
|
+
promptGuidelines: string[];
|
|
63
|
+
parameters: import("@sinclair/typebox").TObject<{
|
|
64
|
+
noteId: import("@sinclair/typebox").TString;
|
|
65
|
+
}>;
|
|
66
|
+
execute(_toolCallId: string, params: NoteShowToolParams): Promise<{
|
|
67
|
+
content: {
|
|
68
|
+
type: "text";
|
|
69
|
+
text: string;
|
|
70
|
+
}[];
|
|
71
|
+
details: NoteShowToolDetails;
|
|
72
|
+
}>;
|
|
73
|
+
};
|
|
74
|
+
declare const registerNoteReadTools: (pi: Pick<ExtensionAPI, "registerTool">, dependencies: NoteReadToolDependencies) => void;
|
|
75
|
+
declare const normalizeNoteListFilter: (params: NoteListToolParams) => NoteFilter;
|
|
76
|
+
declare const formatNoteListContent: (details: NoteListToolDetails) => string;
|
|
77
|
+
declare const formatNoteShowContent: (note: NoteSummary) => string;
|
|
78
|
+
export type { NoteListToolDetails, NoteShowToolDetails, NoteReadToolDependencies };
|
|
79
|
+
export { createNoteListToolDefinition, createNoteShowToolDefinition, formatNoteListContent, formatNoteShowContent, normalizeNoteListFilter, registerNoteReadTools, };
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { StringEnum } from "@mariozechner/pi-ai";
|
|
2
|
+
import { Type } from "@sinclair/typebox";
|
|
3
|
+
import { getSystemTimezone } from "../utils/timezone.js";
|
|
4
|
+
const NOTE_ENTITY_TYPE_VALUES = ["task", "project", "habit"];
|
|
5
|
+
const NoteShowParams = Type.Object({
|
|
6
|
+
noteId: Type.String({ description: "Note ID" }),
|
|
7
|
+
});
|
|
8
|
+
const NoteListParams = Type.Object({
|
|
9
|
+
entityType: Type.Optional(StringEnum(NOTE_ENTITY_TYPE_VALUES, {
|
|
10
|
+
description: "Optional entity type filter (task, project, habit)",
|
|
11
|
+
})),
|
|
12
|
+
entityId: Type.Optional(Type.String({ description: "Optional entity ID filter (task ID, project ID, or habit ID)" })),
|
|
13
|
+
tag: Type.Optional(Type.String({ description: "Optional tag filter" })),
|
|
14
|
+
author: Type.Optional(Type.String({ description: "Optional author filter" })),
|
|
15
|
+
from: Type.Optional(Type.String({ description: "Optional created-at start date (YYYY-MM-DD)" })),
|
|
16
|
+
to: Type.Optional(Type.String({ description: "Optional created-at end date (YYYY-MM-DD)" })),
|
|
17
|
+
journal: Type.Optional(Type.Boolean({ description: "Filter to standalone journal entries only" })),
|
|
18
|
+
timezone: Type.Optional(Type.String({ description: "IANA timezone (auto-detected if omitted)" })),
|
|
19
|
+
});
|
|
20
|
+
const createNoteListToolDefinition = ({ getNoteService }) => ({
|
|
21
|
+
name: "note_list",
|
|
22
|
+
label: "Note List",
|
|
23
|
+
description: "List notes with optional entity type, entity ID, tag, author, date range, and journal filters.",
|
|
24
|
+
promptSnippet: "List notes using structured filters for entity type, entity ID, tag, author, date range, or journal mode.",
|
|
25
|
+
promptGuidelines: [
|
|
26
|
+
"Use this tool for backend note lookups in normal chat.",
|
|
27
|
+
"Use entityType and entityId together to scope notes to a specific task, project, or habit.",
|
|
28
|
+
"Use journal=true to find standalone journal entries without an attached entity.",
|
|
29
|
+
],
|
|
30
|
+
parameters: NoteListParams,
|
|
31
|
+
async execute(_toolCallId, params) {
|
|
32
|
+
const filter = normalizeNoteListFilter(params);
|
|
33
|
+
try {
|
|
34
|
+
const noteService = await getNoteService();
|
|
35
|
+
const notes = await noteService.listNotes(filter);
|
|
36
|
+
const details = {
|
|
37
|
+
kind: "note_list",
|
|
38
|
+
filter,
|
|
39
|
+
notes,
|
|
40
|
+
total: notes.length,
|
|
41
|
+
empty: notes.length === 0,
|
|
42
|
+
};
|
|
43
|
+
return {
|
|
44
|
+
content: [{ type: "text", text: formatNoteListContent(details) }],
|
|
45
|
+
details,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
throw new Error(formatToolError(error, "note_list failed"), { cause: error });
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
const createNoteShowToolDefinition = ({ getNoteService }) => ({
|
|
54
|
+
name: "note_show",
|
|
55
|
+
label: "Note Show",
|
|
56
|
+
description: "Show full note details by note ID.",
|
|
57
|
+
promptSnippet: "Show details for a specific note by note ID.",
|
|
58
|
+
promptGuidelines: [
|
|
59
|
+
"Use this tool when the user asks for details about a known note ID.",
|
|
60
|
+
"If the note is missing, report the explicit not-found result instead of guessing.",
|
|
61
|
+
],
|
|
62
|
+
parameters: NoteShowParams,
|
|
63
|
+
async execute(_toolCallId, params) {
|
|
64
|
+
try {
|
|
65
|
+
const noteService = await getNoteService();
|
|
66
|
+
const note = await noteService.getNote(params.noteId);
|
|
67
|
+
if (!note) {
|
|
68
|
+
const details = {
|
|
69
|
+
kind: "note_show",
|
|
70
|
+
noteId: params.noteId,
|
|
71
|
+
found: false,
|
|
72
|
+
};
|
|
73
|
+
return {
|
|
74
|
+
content: [{ type: "text", text: `Note not found: ${params.noteId}` }],
|
|
75
|
+
details,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const details = {
|
|
79
|
+
kind: "note_show",
|
|
80
|
+
noteId: params.noteId,
|
|
81
|
+
found: true,
|
|
82
|
+
note,
|
|
83
|
+
};
|
|
84
|
+
return {
|
|
85
|
+
content: [{ type: "text", text: formatNoteShowContent(note) }],
|
|
86
|
+
details,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
throw new Error(formatToolError(error, "note_show failed"), { cause: error });
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
const registerNoteReadTools = (pi, dependencies) => {
|
|
95
|
+
pi.registerTool(createNoteListToolDefinition(dependencies));
|
|
96
|
+
pi.registerTool(createNoteShowToolDefinition(dependencies));
|
|
97
|
+
};
|
|
98
|
+
const normalizeNoteListFilter = (params) => ({
|
|
99
|
+
entityType: params.entityType ?? undefined,
|
|
100
|
+
entityId: normalizeOptionalText(params.entityId),
|
|
101
|
+
tag: normalizeOptionalText(params.tag),
|
|
102
|
+
author: normalizeOptionalText(params.author),
|
|
103
|
+
from: normalizeOptionalText(params.from),
|
|
104
|
+
to: normalizeOptionalText(params.to),
|
|
105
|
+
journal: params.journal ?? undefined,
|
|
106
|
+
timezone: normalizeOptionalText(params.timezone) ?? getSystemTimezone(),
|
|
107
|
+
});
|
|
108
|
+
const normalizeOptionalText = (value) => {
|
|
109
|
+
const trimmedValue = value?.trim();
|
|
110
|
+
return trimmedValue && trimmedValue.length > 0 ? trimmedValue : undefined;
|
|
111
|
+
};
|
|
112
|
+
const formatNoteListContent = (details) => {
|
|
113
|
+
if (details.empty) {
|
|
114
|
+
return "No notes found.";
|
|
115
|
+
}
|
|
116
|
+
const lines = [`Notes (${details.total}):`];
|
|
117
|
+
for (const note of details.notes) {
|
|
118
|
+
lines.push(`- ${formatNoteSummaryLine(note)}`);
|
|
119
|
+
}
|
|
120
|
+
return lines.join("\n");
|
|
121
|
+
};
|
|
122
|
+
const formatNoteSummaryLine = (note) => {
|
|
123
|
+
const entityLabel = note.entityType ? `${note.entityType}:${note.entityId ?? "?"}` : "journal";
|
|
124
|
+
const tagLabel = note.tags.length > 0 ? note.tags.join(", ") : "no tags";
|
|
125
|
+
return `${note.id} • ${entityLabel} • ${note.author} • ${tagLabel} • ${note.createdAt}\n ${note.content}`;
|
|
126
|
+
};
|
|
127
|
+
const formatNoteShowContent = (note) => {
|
|
128
|
+
const entityLabel = note.entityType ? `${note.entityType}:${note.entityId ?? "?"}` : "journal";
|
|
129
|
+
const tagLabel = note.tags.length > 0 ? note.tags.join(", ") : "no tags";
|
|
130
|
+
return [
|
|
131
|
+
`Note ${note.id}`,
|
|
132
|
+
"",
|
|
133
|
+
`Author: ${note.author}`,
|
|
134
|
+
`Entity: ${entityLabel}`,
|
|
135
|
+
`Tags: ${tagLabel}`,
|
|
136
|
+
`Created: ${note.createdAt}`,
|
|
137
|
+
"",
|
|
138
|
+
"Content:",
|
|
139
|
+
note.content.trim().length > 0 ? note.content : "(empty)",
|
|
140
|
+
].join("\n");
|
|
141
|
+
};
|
|
142
|
+
const formatToolError = (error, prefix) => {
|
|
143
|
+
if (error instanceof Error && error.message.trim().length > 0) {
|
|
144
|
+
return `${prefix}: ${error.message}`;
|
|
145
|
+
}
|
|
146
|
+
return prefix;
|
|
147
|
+
};
|
|
148
|
+
export { createNoteListToolDefinition, createNoteShowToolDefinition, formatNoteListContent, formatNoteShowContent, normalizeNoteListFilter, registerNoteReadTools, };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
2
|
+
import type { ProjectSummary, TaskPriority } from "../domain/task";
|
|
3
|
+
import type { IntegrationBinding, ProjectIntegrationService, RegisterRepositoryProjectInput } from "../services/project-integration-service";
|
|
4
|
+
import type { ProjectService } from "../services/project-service";
|
|
5
|
+
import type { ResolvedRepositoryContext } from "../services/repo-context";
|
|
6
|
+
interface ProjectCheckToolParams {
|
|
7
|
+
repositoryPath?: string;
|
|
8
|
+
provider?: string;
|
|
9
|
+
targetRef?: string;
|
|
10
|
+
}
|
|
11
|
+
interface ProjectRegisterToolParams extends ProjectCheckToolParams {
|
|
12
|
+
projectName?: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
priority?: TaskPriority;
|
|
15
|
+
}
|
|
16
|
+
interface ProjectCheckToolDetails {
|
|
17
|
+
kind: "project_check";
|
|
18
|
+
state: "registered" | "not-registered" | "ambiguous" | "missing-context" | "unsupported";
|
|
19
|
+
repositoryPath?: string;
|
|
20
|
+
repository?: ResolvedRepositoryContext;
|
|
21
|
+
reason?: string;
|
|
22
|
+
project?: ProjectSummary | null;
|
|
23
|
+
binding?: IntegrationBinding;
|
|
24
|
+
bindings?: IntegrationBinding[];
|
|
25
|
+
remotes?: string[];
|
|
26
|
+
}
|
|
27
|
+
interface ProjectRegisterToolDetails {
|
|
28
|
+
kind: "project_register";
|
|
29
|
+
state: "registered" | "already-registered" | "name-conflict" | "ambiguous" | "missing-context" | "unsupported";
|
|
30
|
+
repositoryPath?: string;
|
|
31
|
+
repository?: ResolvedRepositoryContext;
|
|
32
|
+
project?: ProjectSummary | null;
|
|
33
|
+
binding?: IntegrationBinding;
|
|
34
|
+
createdProject?: boolean;
|
|
35
|
+
createdBinding?: boolean;
|
|
36
|
+
conflictingProjects?: ProjectSummary[];
|
|
37
|
+
reason?: string;
|
|
38
|
+
remotes?: string[];
|
|
39
|
+
bindings?: IntegrationBinding[];
|
|
40
|
+
}
|
|
41
|
+
interface ProjectIntegrationToolDependencies {
|
|
42
|
+
getProjectIntegrationService: () => Promise<ProjectIntegrationService>;
|
|
43
|
+
getProjectService: () => Promise<ProjectService>;
|
|
44
|
+
}
|
|
45
|
+
declare const createProjectCheckToolDefinition: ({ getProjectIntegrationService, }: Pick<ProjectIntegrationToolDependencies, "getProjectIntegrationService">) => {
|
|
46
|
+
name: string;
|
|
47
|
+
label: string;
|
|
48
|
+
description: string;
|
|
49
|
+
promptSnippet: string;
|
|
50
|
+
promptGuidelines: string[];
|
|
51
|
+
parameters: import("@sinclair/typebox").TObject<{
|
|
52
|
+
repositoryPath: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
53
|
+
provider: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
54
|
+
targetRef: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
55
|
+
}>;
|
|
56
|
+
execute(_toolCallId: string, params: ProjectCheckToolParams): Promise<{
|
|
57
|
+
content: {
|
|
58
|
+
type: "text";
|
|
59
|
+
text: string;
|
|
60
|
+
}[];
|
|
61
|
+
details: ProjectCheckToolDetails;
|
|
62
|
+
}>;
|
|
63
|
+
};
|
|
64
|
+
declare const createProjectRegisterToolDefinition: ({ getProjectIntegrationService, getProjectService, }: ProjectIntegrationToolDependencies) => {
|
|
65
|
+
name: string;
|
|
66
|
+
label: string;
|
|
67
|
+
description: string;
|
|
68
|
+
promptSnippet: string;
|
|
69
|
+
promptGuidelines: string[];
|
|
70
|
+
parameters: import("@sinclair/typebox").TObject<{
|
|
71
|
+
projectName: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
72
|
+
repositoryPath: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
73
|
+
provider: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
74
|
+
targetRef: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
75
|
+
description: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
76
|
+
priority: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnsafe<"low" | "medium" | "high">>;
|
|
77
|
+
}>;
|
|
78
|
+
execute(_toolCallId: string, params: ProjectRegisterToolParams): Promise<{
|
|
79
|
+
content: {
|
|
80
|
+
type: "text";
|
|
81
|
+
text: string;
|
|
82
|
+
}[];
|
|
83
|
+
details: ProjectRegisterToolDetails;
|
|
84
|
+
}>;
|
|
85
|
+
};
|
|
86
|
+
declare const registerProjectIntegrationTools: (pi: Pick<ExtensionAPI, "registerTool">, dependencies: ProjectIntegrationToolDependencies) => void;
|
|
87
|
+
declare const normalizeProjectCheckInput: (params: ProjectCheckToolParams) => ProjectCheckToolParams;
|
|
88
|
+
declare const normalizeProjectRegisterInput: (params: ProjectRegisterToolParams) => RegisterRepositoryProjectInput;
|
|
89
|
+
declare const formatProjectCheckContent: (details: ProjectCheckToolDetails) => string;
|
|
90
|
+
declare const formatProjectRegisterContent: (details: ProjectRegisterToolDetails) => string;
|
|
91
|
+
export type { ProjectCheckToolDetails, ProjectIntegrationToolDependencies, ProjectRegisterToolDetails, };
|
|
92
|
+
export { createProjectCheckToolDefinition, createProjectRegisterToolDefinition, formatProjectCheckContent, formatProjectRegisterContent, normalizeProjectCheckInput, normalizeProjectRegisterInput, registerProjectIntegrationTools, };
|