@dain-os/mcp-server 0.20.0 → 0.21.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.
Files changed (58) hide show
  1. package/dist/index.js +0 -0
  2. package/dist/meta.d.ts +1 -1
  3. package/dist/meta.js +1 -1
  4. package/dist/tools/cadence.d.ts +4 -0
  5. package/dist/tools/cadence.d.ts.map +1 -0
  6. package/dist/tools/cadence.js +245 -0
  7. package/dist/tools/cadence.js.map +1 -0
  8. package/dist/tools/comments.d.ts +3 -0
  9. package/dist/tools/comments.d.ts.map +1 -0
  10. package/dist/tools/comments.js +19 -0
  11. package/dist/tools/comments.js.map +1 -0
  12. package/dist/tools/developer.d.ts +3 -0
  13. package/dist/tools/developer.d.ts.map +1 -0
  14. package/dist/tools/developer.js +349 -0
  15. package/dist/tools/developer.js.map +1 -0
  16. package/dist/tools/iam.d.ts +3 -0
  17. package/dist/tools/iam.d.ts.map +1 -0
  18. package/dist/tools/iam.js +38 -0
  19. package/dist/tools/iam.js.map +1 -0
  20. package/dist/tools/log-time-entry.d.ts +3 -0
  21. package/dist/tools/log-time-entry.d.ts.map +1 -0
  22. package/dist/tools/log-time-entry.js +54 -0
  23. package/dist/tools/log-time-entry.js.map +1 -0
  24. package/dist/tools/pr-review.d.ts +3 -0
  25. package/dist/tools/pr-review.d.ts.map +1 -0
  26. package/dist/tools/pr-review.js +83 -0
  27. package/dist/tools/pr-review.js.map +1 -0
  28. package/dist/tools/products.d.ts +3 -0
  29. package/dist/tools/products.d.ts.map +1 -0
  30. package/dist/tools/products.js +37 -0
  31. package/dist/tools/products.js.map +1 -0
  32. package/dist/tools/projects.d.ts +3 -0
  33. package/dist/tools/projects.d.ts.map +1 -0
  34. package/dist/tools/projects.js +151 -0
  35. package/dist/tools/projects.js.map +1 -0
  36. package/dist/tools/proposal-content.d.ts +3 -0
  37. package/dist/tools/proposal-content.d.ts.map +1 -0
  38. package/dist/tools/proposal-content.js +136 -0
  39. package/dist/tools/proposal-content.js.map +1 -0
  40. package/dist/tools/proposal-options.d.ts +3 -0
  41. package/dist/tools/proposal-options.d.ts.map +1 -0
  42. package/dist/tools/proposal-options.js +132 -0
  43. package/dist/tools/proposal-options.js.map +1 -0
  44. package/dist/tools/proposals.d.ts +22 -0
  45. package/dist/tools/proposals.d.ts.map +1 -0
  46. package/dist/tools/proposals.js +179 -0
  47. package/dist/tools/proposals.js.map +1 -0
  48. package/dist/tools/registry.d.ts.map +1 -1
  49. package/dist/tools/registry.js +15 -4
  50. package/dist/tools/registry.js.map +1 -1
  51. package/dist/tools/semantic/tasks.d.ts.map +1 -1
  52. package/dist/tools/semantic/tasks.js +9 -2
  53. package/dist/tools/semantic/tasks.js.map +1 -1
  54. package/dist/tools/tasks.d.ts +3 -0
  55. package/dist/tools/tasks.d.ts.map +1 -0
  56. package/dist/tools/tasks.js +255 -0
  57. package/dist/tools/tasks.js.map +1 -0
  58. package/package.json +1 -1
@@ -0,0 +1,349 @@
1
+ import { z } from 'zod';
2
+ import { logTimeEntryTool } from './log-time-entry.js';
3
+ /**
4
+ * Developer KB tools. Five operations: log_changelog_entry, log_session_context,
5
+ * log_knowledge_base_entry, list_recent_sessions, search_knowledge_base.
6
+ *
7
+ * These back the /wrapup, /recap, and /dev-kb slash commands. The slash command
8
+ * still does the conversation analysis (parsing decisions, lessons, etc.); the
9
+ * tools here are the persistence + retrieval surface. With these in place a
10
+ * developer needs only the DainOS MCP installed — no Supabase MCP token — and
11
+ * the workflows port to any MCP client (Cursor, Continue, etc.).
12
+ *
13
+ * All tools are cross-project: the caller supplies `project` (e.g. "dain-os",
14
+ * "herbert", "mabel") on every call. The backing tables live in the developer
15
+ * schema and span tenants.
16
+ */
17
+ /**
18
+ * Some MCP clients serialise array-typed tool arguments as JSON-encoded strings
19
+ * rather than nested arrays. Caught during /wrapup on 2026-05-14:
20
+ * `log_changelog_entry` rejected a perfectly-shaped batch with "expected array,
21
+ * received string" while `log_knowledge_base_entry` accepted the same shape.
22
+ * The difference was the model's serialisation choice on that specific tool
23
+ * call, not the schema. Defending the entries field at the parse boundary
24
+ * makes both spellings work.
25
+ */
26
+ function jsonStringArray(item, min = 1, max = 50) {
27
+ return z.preprocess((val) => {
28
+ if (typeof val === 'string') {
29
+ try {
30
+ return JSON.parse(val);
31
+ }
32
+ catch {
33
+ return val;
34
+ }
35
+ }
36
+ return val;
37
+ }, z.array(item).min(min).max(max));
38
+ }
39
+ /**
40
+ * Optional string that also accepts `null`. Some clients send `null` for
41
+ * "field intentionally absent" rather than omitting the key; the previous
42
+ * `z.string().optional()` rejected null with "expected string, received null".
43
+ */
44
+ const optionalString = z.preprocess((val) => (val === null ? undefined : val), z.string().optional());
45
+ /** Optional non-string field (e.g. number, boolean, array) that accepts null too. */
46
+ function nullishOptional(schema) {
47
+ return z.preprocess((val) => (val === null ? undefined : val), schema.optional());
48
+ }
49
+ const commitTypeEnum = z.enum([
50
+ 'feat', 'fix', 'chore', 'refactor', 'test', 'docs', 'perf', 'ci', 'build', 'revert', 'style',
51
+ ]);
52
+ const sourceTypeEnum = z.enum([
53
+ 'fix_commit', 'pr_comment', 'pr_review', 'code_review',
54
+ 'ai_conversation', 'incident', 'documentation', 'debugging_session',
55
+ ]);
56
+ const severityEnum = z.enum(['critical', 'high', 'medium', 'low']);
57
+ const kbCategoryEnum = z.enum(['gotcha', 'pattern', 'lesson', 'decision', 'workaround']);
58
+ // ---------------------------------------------------------------------------
59
+ // log_changelog_entry — batch insert of commit records
60
+ // ---------------------------------------------------------------------------
61
+ const changelogEntrySchema = z.object({
62
+ commit_sha: z.string().length(40).describe('Full 40-character SHA.'),
63
+ branch: optionalString.describe('Defaults to "main" if omitted.'),
64
+ commit_type: commitTypeEnum.describe('Conventional-commit type prefix.'),
65
+ scope: optionalString,
66
+ summary: z.string().describe('Commit message subject line.'),
67
+ description: optionalString,
68
+ files_changed: nullishOptional(z.coerce.number().int()),
69
+ insertions: nullishOptional(z.coerce.number().int()),
70
+ deletions: nullishOptional(z.coerce.number().int()),
71
+ milestone: optionalString,
72
+ task_ref: optionalString.describe('Linear / Jira / Notion task id.'),
73
+ impacts_config: nullishOptional(z.boolean()).describe('Defaults false.'),
74
+ breaking_change: nullishOptional(z.boolean()).describe('Defaults false.'),
75
+ tags: nullishOptional(z.array(z.string())),
76
+ author: optionalString,
77
+ committed_at: z.string().describe('ISO 8601 timestamp.'),
78
+ pr_number: nullishOptional(z.coerce.number().int()),
79
+ pr_url: optionalString,
80
+ });
81
+ const logChangelogEntry = {
82
+ name: 'log_changelog_entry',
83
+ description: 'Append commit records to the developer changelog for a project. Use during /wrapup to persist today\'s commits. Accepts a batch (1-50 entries). Idempotent on (project, commit_sha): duplicates are silently skipped. Returns { inserted, skipped } counts.',
84
+ inputSchema: z.object({
85
+ project: z.string().describe('Project slug, e.g. "dain-os", "herbert", "mabel".'),
86
+ entries: jsonStringArray(changelogEntrySchema, 1, 50),
87
+ }),
88
+ handler: async (client, input) => {
89
+ const entries = input.entries.map((entry) => ({
90
+ ...entry,
91
+ project: input.project,
92
+ }));
93
+ return client.post('/developer/changelog', { entries });
94
+ },
95
+ };
96
+ // ---------------------------------------------------------------------------
97
+ // log_session_context — single session insert
98
+ // ---------------------------------------------------------------------------
99
+ const decisionSchema = z.object({
100
+ decision: z.string(),
101
+ reason: z.string(),
102
+ });
103
+ const logSessionContext = {
104
+ name: 'log_session_context',
105
+ description: 'Record a single development session for a project (one row per session). Captures decisions made, files touched, blockers, and handoff notes. Use during /wrapup to leave breadcrumbs for the next session. Read back via list_recent_sessions during /recap.',
106
+ inputSchema: z.object({
107
+ project: z.string().describe('Project slug, e.g. "dain-os".'),
108
+ session_name: z.string().describe('Short descriptive title.'),
109
+ session_date: optionalString.describe('YYYY-MM-DD. Defaults to today server-side.'),
110
+ operator: z.string().describe('e.g. "Dane + Claude Opus 4.7".'),
111
+ machine: optionalString,
112
+ duration_minutes: nullishOptional(z.coerce.number().int()),
113
+ summary: z.string().describe('2-4 sentence overview of WHAT and WHY.'),
114
+ decisions_made: nullishOptional(z.array(decisionSchema)).describe('Non-obvious choices future sessions need to understand.'),
115
+ files_touched: nullishOptional(z.array(z.string())),
116
+ tasks_completed: nullishOptional(z.array(z.string())),
117
+ blockers: nullishOptional(z.array(z.string())),
118
+ handoff_notes: optionalString.describe('What the next session needs to know first.'),
119
+ tags: nullishOptional(z.array(z.string())),
120
+ client_visible: nullishOptional(z.boolean()).describe('When false, the session is hidden from portal product pages and the client portal activity feed. Defaults to true. Set false for sensitive sessions (security incidents, internal escalations).'),
121
+ product_id: nullishOptional(z.string().uuid()).describe('UUID of the product this session relates to.'),
122
+ task_ids: nullishOptional(z.array(z.string().uuid()).max(100)).describe('UUIDs of DainOS tasks worked on during the session (max 100).'),
123
+ operator_iam_user_id: nullishOptional(z.string().uuid()).describe('IAM user UUID of the operator. Resolved server-side from the auth token when omitted.'),
124
+ }),
125
+ handler: async (client, input) => client.post('/developer/sessions', input),
126
+ };
127
+ // ---------------------------------------------------------------------------
128
+ // log_knowledge_base_entry — batch insert of KB findings
129
+ // ---------------------------------------------------------------------------
130
+ const kbEntrySchema = z.object({
131
+ category: kbCategoryEnum,
132
+ module: z.string().describe('System / area, e.g. "auth", "react", "prisma".'),
133
+ title: z.string().describe('Short descriptive title.'),
134
+ description: z.string().describe('What happened / what is this.'),
135
+ impact: optionalString.describe('What goes wrong if you don\'t know this.'),
136
+ prevention: optionalString.describe('How to avoid it next time.'),
137
+ severity: nullishOptional(severityEnum),
138
+ source_type: sourceTypeEnum,
139
+ source_refs: nullishOptional(z.array(z.string())).describe('Links, file paths, or commit SHAs.'),
140
+ tags: nullishOptional(z.array(z.string())),
141
+ platform: optionalString.describe('e.g. "supabase", "anthropic", "vercel".'),
142
+ });
143
+ const logKnowledgeBaseEntry = {
144
+ name: 'log_knowledge_base_entry',
145
+ description: 'Append KB findings (gotchas, patterns, lessons, decisions, workarounds) for a project. Only add entries for things that were SURPRISING, NON-OBVIOUS, or caused real problems. Use during /wrapup. Accepts a batch (1-50 entries). Check for similar existing titles via search_knowledge_base before adding to avoid duplicates.',
146
+ inputSchema: z.object({
147
+ project: z.string().describe('Project slug, e.g. "dain-os". Use "universal" for cross-product lessons.'),
148
+ entries: jsonStringArray(kbEntrySchema, 1, 50),
149
+ }),
150
+ handler: async (client, input) => {
151
+ const entries = input.entries.map((entry) => ({
152
+ ...entry,
153
+ project: input.project,
154
+ }));
155
+ return client.post('/developer/knowledge-base', { entries });
156
+ },
157
+ };
158
+ // ---------------------------------------------------------------------------
159
+ // list_recent_sessions — read recent sessions for /recap
160
+ // ---------------------------------------------------------------------------
161
+ const listRecentSessions = {
162
+ name: 'list_recent_sessions',
163
+ description: 'List the most recent development sessions for a project, newest first. Use during /recap to brief the user on what happened in the last 1-N sessions. Returns full session_context rows including decisions, blockers, and handoff_notes.',
164
+ inputSchema: z.object({
165
+ project: z.string().describe('Project slug.'),
166
+ limit: z.coerce.number().int().min(1).max(50).optional().describe('Default 10, max 50.'),
167
+ offset: z.coerce.number().int().min(0).optional().describe('For pagination.'),
168
+ }),
169
+ handler: async (client, input) => {
170
+ const params = new URLSearchParams();
171
+ params.set('project', input.project);
172
+ if (input.limit !== undefined)
173
+ params.set('limit', String(input.limit));
174
+ if (input.offset !== undefined)
175
+ params.set('offset', String(input.offset));
176
+ return client.get(`/developer/sessions?${params.toString()}`);
177
+ },
178
+ };
179
+ // ---------------------------------------------------------------------------
180
+ // search_knowledge_base — read KB by project/module/severity/keyword
181
+ // ---------------------------------------------------------------------------
182
+ const searchKnowledgeBase = {
183
+ name: 'search_knowledge_base',
184
+ description: 'Search the developer KB for relevant gotchas, patterns, lessons, decisions, and workarounds. Use before writing code in a module (catches existing gotchas), during /dev-kb invocations, and before /wrapup to dedupe. Filters AND together; `q` is a case-insensitive substring match against title and description.',
185
+ inputSchema: z.object({
186
+ project: z.string().describe('Project slug. Filter by "universal" for cross-product entries.'),
187
+ module: z.string().optional().describe('e.g. "auth", "react", "prisma".'),
188
+ category: kbCategoryEnum.optional(),
189
+ severity: severityEnum.optional(),
190
+ q: z.string().optional().describe('Free-text match against title + description.'),
191
+ limit: z.coerce.number().int().min(1).max(50).optional().describe('Default 10.'),
192
+ offset: z.coerce.number().int().min(0).optional(),
193
+ }),
194
+ handler: async (client, input) => {
195
+ const params = new URLSearchParams();
196
+ params.set('project', input.project);
197
+ if (input.module)
198
+ params.set('module', input.module);
199
+ if (input.category)
200
+ params.set('category', input.category);
201
+ if (input.severity)
202
+ params.set('severity', input.severity);
203
+ if (input.q)
204
+ params.set('q', input.q);
205
+ if (input.limit !== undefined)
206
+ params.set('limit', String(input.limit));
207
+ if (input.offset !== undefined)
208
+ params.set('offset', String(input.offset));
209
+ return client.get(`/developer/knowledge-base/search?${params.toString()}`);
210
+ },
211
+ };
212
+ // ---------------------------------------------------------------------------
213
+ // update_* — partial edits to existing developer KB rows
214
+ // ---------------------------------------------------------------------------
215
+ //
216
+ // Wraps PATCH /developer/{changelog|sessions|knowledge-base}/:id. Used when a
217
+ // /wrapup-style flow needs to amend a previously-logged entry (e.g. the user
218
+ // corrects a session summary, fills in handoff_notes after the fact, or
219
+ // reclassifies a KB entry's severity). `project` is immutable on every row —
220
+ // to "move" between projects, delete and re-insert.
221
+ const updateChangelogEntry = {
222
+ name: 'update_changelog_entry',
223
+ description: 'Partially update an existing changelog entry by id. Every field is optional; only the supplied fields are written. `project` and `commit_sha` are immutable. Returns the refreshed row. 404 if id is unknown.',
224
+ inputSchema: z.object({
225
+ id: z.string().uuid().describe('Changelog entry id (UUID).'),
226
+ branch: optionalString,
227
+ commit_type: commitTypeEnum.optional(),
228
+ scope: optionalString,
229
+ summary: optionalString,
230
+ description: optionalString,
231
+ files_changed: nullishOptional(z.coerce.number().int()),
232
+ insertions: nullishOptional(z.coerce.number().int()),
233
+ deletions: nullishOptional(z.coerce.number().int()),
234
+ milestone: optionalString,
235
+ task_ref: optionalString,
236
+ impacts_config: nullishOptional(z.boolean()),
237
+ breaking_change: nullishOptional(z.boolean()),
238
+ tags: nullishOptional(z.array(z.string())),
239
+ author: optionalString,
240
+ committed_at: optionalString.describe('ISO 8601 timestamp.'),
241
+ pr_number: nullishOptional(z.coerce.number().int()),
242
+ pr_url: optionalString,
243
+ }),
244
+ handler: async (client, input) => {
245
+ const { id, ...rest } = input;
246
+ // Drop undefined keys so the API only receives the fields the caller set.
247
+ const body = Object.fromEntries(Object.entries(rest).filter(([, value]) => value !== undefined));
248
+ return client.patch(`/developer/changelog/${id}`, body);
249
+ },
250
+ };
251
+ const updateSessionContext = {
252
+ name: 'update_session_context',
253
+ description: 'Partially update an existing session_context row by id. Every field is optional. `project` is immutable. Returns the refreshed row. 404 if id is unknown.',
254
+ inputSchema: z.object({
255
+ id: z.string().uuid().describe('Session context id (UUID).'),
256
+ session_name: optionalString,
257
+ session_date: optionalString.describe('YYYY-MM-DD.'),
258
+ operator: optionalString,
259
+ machine: optionalString,
260
+ duration_minutes: nullishOptional(z.coerce.number().int()),
261
+ summary: optionalString,
262
+ decisions_made: nullishOptional(z.array(decisionSchema)),
263
+ files_touched: nullishOptional(z.array(z.string())),
264
+ tasks_completed: nullishOptional(z.array(z.string())),
265
+ blockers: nullishOptional(z.array(z.string())),
266
+ handoff_notes: optionalString,
267
+ tags: nullishOptional(z.array(z.string())),
268
+ product_id: nullishOptional(z.string().uuid()).describe('UUID of the product this session relates to.'),
269
+ task_ids: nullishOptional(z.array(z.string().uuid()).max(100)).describe('UUIDs of DainOS tasks worked on during the session (max 100).'),
270
+ operator_iam_user_id: nullishOptional(z.string().uuid()).describe('IAM user UUID of the operator.'),
271
+ }),
272
+ handler: async (client, input) => {
273
+ const { id, ...rest } = input;
274
+ const body = Object.fromEntries(Object.entries(rest).filter(([, value]) => value !== undefined));
275
+ return client.patch(`/developer/sessions/${id}`, body);
276
+ },
277
+ };
278
+ const updateKnowledgeBaseEntry = {
279
+ name: 'update_knowledge_base_entry',
280
+ description: 'Partially update an existing KB entry by id. Every field is optional. `project` is immutable. Returns the refreshed row. 404 if id is unknown.',
281
+ inputSchema: z.object({
282
+ id: z.string().uuid().describe('KB entry id (UUID).'),
283
+ category: kbCategoryEnum.optional(),
284
+ module: optionalString,
285
+ title: optionalString,
286
+ description: optionalString,
287
+ impact: optionalString,
288
+ prevention: optionalString,
289
+ severity: nullishOptional(severityEnum),
290
+ source_type: sourceTypeEnum.optional(),
291
+ source_refs: nullishOptional(z.array(z.string())),
292
+ tags: nullishOptional(z.array(z.string())),
293
+ platform: optionalString,
294
+ }),
295
+ handler: async (client, input) => {
296
+ const { id, ...rest } = input;
297
+ const body = Object.fromEntries(Object.entries(rest).filter(([, value]) => value !== undefined));
298
+ return client.patch(`/developer/knowledge-base/${id}`, body);
299
+ },
300
+ };
301
+ // ---------------------------------------------------------------------------
302
+ // list_changelog — read changelog entries by project slug + date
303
+ // ---------------------------------------------------------------------------
304
+ const listChangelog = {
305
+ name: 'list_changelog',
306
+ description: 'List developer changelog entries for a project, newest first. Optionally filter by `since` (ISO 8601 date). Default limit 50, max 200. Use during /recap to review recent commits for a project without raw SQL.',
307
+ inputSchema: z.object({
308
+ project: z
309
+ .string()
310
+ .min(1)
311
+ .max(100)
312
+ .regex(/^[a-z0-9][a-z0-9-]*$/, 'project must be a lowercase slug')
313
+ .describe('Project slug, e.g. "dain-os", "herbert", "mabel".'),
314
+ since: z
315
+ .string()
316
+ .datetime({ offset: true, message: 'since must be ISO 8601 with offset' })
317
+ .optional()
318
+ .describe('ISO 8601 timestamp with offset (e.g. 2026-05-18T00:00:00Z) — only return entries with committed_at >= this value.'),
319
+ limit: z.coerce
320
+ .number()
321
+ .int()
322
+ .min(1)
323
+ .max(200)
324
+ .optional()
325
+ .describe('Default 50, max 200.'),
326
+ }),
327
+ handler: async (client, input) => {
328
+ const params = new URLSearchParams();
329
+ params.set('project', input.project);
330
+ if (input.since)
331
+ params.set('since', input.since);
332
+ if (input.limit !== undefined)
333
+ params.set('limit', String(input.limit));
334
+ return client.get(`/developer/changelog?${params.toString()}`);
335
+ },
336
+ };
337
+ export const developerTools = [
338
+ logChangelogEntry,
339
+ logSessionContext,
340
+ logKnowledgeBaseEntry,
341
+ listRecentSessions,
342
+ searchKnowledgeBase,
343
+ updateChangelogEntry,
344
+ updateSessionContext,
345
+ updateKnowledgeBaseEntry,
346
+ listChangelog,
347
+ logTimeEntryTool,
348
+ ];
349
+ //# sourceMappingURL=developer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"developer.js","sourceRoot":"","sources":["../../src/tools/developer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ToolDefinition } from './types.js';
2
+ export declare const iamTools: ToolDefinition[];
3
+ //# sourceMappingURL=iam.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iam.d.ts","sourceRoot":"","sources":["../../src/tools/iam.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAyCjD,eAAO,MAAM,QAAQ,EAAE,cAAc,EAA+B,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * IAM user tools — operator-identity helpers for the wrap-up skill.
4
+ *
5
+ * Both tools are intentionally tenant-scoped at the API layer: the server
6
+ * resolves the caller's tenant from their JWT/PAT and filters iam.users
7
+ * automatically via the Prisma tenant extension. No tenantSlug param is
8
+ * accepted here because that would introduce a foot-gun: a caller who
9
+ * guesses another tenant's slug would get a 403 at worst, but the API
10
+ * simply ignores slug params and always scopes to the caller's tenant.
11
+ */
12
+ const listTenantUsers = {
13
+ name: 'list_tenant_users',
14
+ description: 'List users in the caller\'s tenant. Returns id, email, fullName, displayName, status, and tenantId for each user, ordered by fullName. Optionally filter by status (active | inactive | suspended | pending). Use this to look up who to attribute work to in the wrap-up flow.',
15
+ inputSchema: z.object({
16
+ status: z
17
+ .enum(['active', 'inactive', 'suspended', 'pending'])
18
+ .optional()
19
+ .describe('Filter by user status. Omit to return all statuses.'),
20
+ }),
21
+ handler: async (client, input) => {
22
+ const params = new URLSearchParams();
23
+ if (input.status)
24
+ params.set('status', input.status);
25
+ const query = params.toString() ? `?${params.toString()}` : '';
26
+ return client.get(`/iam/users${query}`);
27
+ },
28
+ };
29
+ const getUser = {
30
+ name: 'get_user',
31
+ description: 'Get one user by id from the caller\'s tenant. Returns id, email, fullName, displayName, status, and tenantId. Returns a 404 error if the id is unknown or belongs to a different tenant.',
32
+ inputSchema: z.object({
33
+ id: z.string().uuid().describe('The iam_users UUID of the user to fetch.'),
34
+ }),
35
+ handler: async (client, input) => client.get(`/iam/users/${input.id}`),
36
+ };
37
+ export const iamTools = [listTenantUsers, getUser];
38
+ //# sourceMappingURL=iam.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iam.js","sourceRoot":"","sources":["../../src/tools/iam.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;;;;;;GASG;AAEH,MAAM,eAAe,GAAmB;IACtC,IAAI,EAAE,mBAAmB;IACzB,WAAW,EACT,iRAAiR;IACnR,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,MAAM,EAAE,CAAC;aACN,IAAI,CAAC,CAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;aACpD,QAAQ,EAAE;aACV,QAAQ,CAAC,qDAAqD,CAAC;KACnE,CAAC;IACF,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE;QAC/B,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;QACrC,IAAI,KAAK,CAAC,MAAM;YAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QACrD,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,OAAO,MAAM,CAAC,GAAG,CAAC,aAAa,KAAK,EAAE,CAAC,CAAC;IAC1C,CAAC;CACF,CAAC;AAEF,MAAM,OAAO,GAAmB;IAC9B,IAAI,EAAE,UAAU;IAChB,WAAW,EACT,0LAA0L;IAC5L,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,0CAA0C,CAAC;KAC3E,CAAC;IACF,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,KAAK,CAAC,EAAE,EAAE,CAAC;CACvE,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAqB,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ToolDefinition } from './types.js';
2
+ export declare const logTimeEntryTool: ToolDefinition;
3
+ //# sourceMappingURL=log-time-entry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-time-entry.d.ts","sourceRoot":"","sources":["../../src/tools/log-time-entry.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,eAAO,MAAM,gBAAgB,EAAE,cAiD9B,CAAC"}
@@ -0,0 +1,54 @@
1
+ // packages/mcp-server/src/tools/log-time-entry.ts
2
+ //
3
+ // MCP tool: log_time_entry
4
+ // Feature Brief §9.3 — called by the wrap-up skill immediately after
5
+ // log_session_context. Idempotent on sessionContextId.
6
+ //
7
+ // Input schema mirrors logTimeEntryInputSchema in
8
+ // apps/api/src/domains/developer/types/developer.types.ts exactly.
9
+ // Handler calls POST /api/v1/developer/time-entries.
10
+ import { z } from 'zod';
11
+ export const logTimeEntryTool = {
12
+ name: 'log_time_entry',
13
+ description: 'Log a time entry for a development session against a project slug. Used by the /wrap-up skill immediately after log_session_context. Idempotent on sessionContextId: re-calling with the same sessionContextId returns the existing entry with alreadyExisted: true.',
14
+ inputSchema: z.object({
15
+ operatorIamUserId: z
16
+ .string()
17
+ .uuid()
18
+ .describe('iam_users.id of the person who ran the session. NOT the Supabase auth UUID — resolve from your wrap-up config.'),
19
+ sessionContextId: z
20
+ .string()
21
+ .uuid()
22
+ .describe('UUID returned by log_session_context. Acts as the idempotency key.'),
23
+ projectSlug: z
24
+ .string()
25
+ .min(1)
26
+ .max(200)
27
+ .describe('The project slug (e.g. dain-os, herbert, mabel). Resolved via session_slug_aliases server-side.'),
28
+ taskIds: z
29
+ .array(z.string().uuid())
30
+ .default([])
31
+ .describe('UUIDs of DainOS tasks worked during the session. If exactly one, it is written to task_id. Defaults to [].'),
32
+ durationMinutes: z
33
+ .number()
34
+ .int()
35
+ .positive()
36
+ .max(1440)
37
+ .describe('Duration of the session in whole minutes (1 to 1440).'),
38
+ entryDate: z
39
+ .string()
40
+ .regex(/^\d{4}-\d{2}-\d{2}$/)
41
+ .describe('Calendar date of the session in YYYY-MM-DD format.'),
42
+ description: z
43
+ .string()
44
+ .max(500)
45
+ .optional()
46
+ .describe('Optional human-readable summary of what was done. Max 500 characters.'),
47
+ isBillable: z
48
+ .boolean()
49
+ .default(false)
50
+ .describe('Whether the session is billable to a client. Defaults to false.'),
51
+ }),
52
+ handler: async (client, input) => client.post('/developer/time-entries', input),
53
+ };
54
+ //# sourceMappingURL=log-time-entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-time-entry.js","sourceRoot":"","sources":["../../src/tools/log-time-entry.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,EAAE;AACF,2BAA2B;AAC3B,qEAAqE;AACrE,uDAAuD;AACvD,EAAE;AACF,kDAAkD;AAClD,mEAAmE;AACnE,qDAAqD;AAErD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,CAAC,MAAM,gBAAgB,GAAmB;IAC9C,IAAI,EAAE,gBAAgB;IACtB,WAAW,EACT,sQAAsQ;IACxQ,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,iBAAiB,EAAE,CAAC;aACjB,MAAM,EAAE;aACR,IAAI,EAAE;aACN,QAAQ,CACP,gHAAgH,CACjH;QACH,gBAAgB,EAAE,CAAC;aAChB,MAAM,EAAE;aACR,IAAI,EAAE;aACN,QAAQ,CAAC,oEAAoE,CAAC;QACjF,WAAW,EAAE,CAAC;aACX,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,GAAG,CAAC;aACR,QAAQ,CACP,iGAAiG,CAClG;QACH,OAAO,EAAE,CAAC;aACP,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC;aACxB,OAAO,CAAC,EAAE,CAAC;aACX,QAAQ,CACP,4GAA4G,CAC7G;QACH,eAAe,EAAE,CAAC;aACf,MAAM,EAAE;aACR,GAAG,EAAE;aACL,QAAQ,EAAE;aACV,GAAG,CAAC,IAAI,CAAC;aACT,QAAQ,CAAC,uDAAuD,CAAC;QACpE,SAAS,EAAE,CAAC;aACT,MAAM,EAAE;aACR,KAAK,CAAC,qBAAqB,CAAC;aAC5B,QAAQ,CAAC,oDAAoD,CAAC;QACjE,WAAW,EAAE,CAAC;aACX,MAAM,EAAE;aACR,GAAG,CAAC,GAAG,CAAC;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,uEAAuE,CAAC;QACpF,UAAU,EAAE,CAAC;aACV,OAAO,EAAE;aACT,OAAO,CAAC,KAAK,CAAC;aACd,QAAQ,CAAC,iEAAiE,CAAC;KAC/E,CAAC;IACF,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,EAAE,KAAK,CAAC;CAChF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ToolDefinition } from './types.js';
2
+ export declare const prReviewTools: ToolDefinition[];
3
+ //# sourceMappingURL=pr-review.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pr-review.d.ts","sourceRoot":"","sources":["../../src/tools/pr-review.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAuFjD,eAAO,MAAM,aAAa,EAAE,cAAc,EAGzC,CAAC"}
@@ -0,0 +1,83 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * PR-review feedback tools for the wrap-up skill Step 7.5.
4
+ *
5
+ * Two operations:
6
+ * list_unscored_pr_findings — fetch findings for a PR that the caller has not yet scored
7
+ * score_pr_finding — record a verdict (useful | noise | wrong) for one finding
8
+ *
9
+ * The verdict enum matches the DB CHECK constraint exactly:
10
+ * 'useful' | 'noise' | 'wrong'
11
+ * 'Skip' is a UI-only sentinel and is intentionally excluded.
12
+ */
13
+ // Matches the DB CHECK constraint: verdict IN ('useful', 'noise', 'wrong')
14
+ const verdictEnum = z.enum(['useful', 'noise', 'wrong']);
15
+ const listUnscoredPrFindings = {
16
+ name: 'list_unscored_pr_findings',
17
+ description: 'List DainOS-reviewer findings on a specific PR that have not yet been scored by the caller. ' +
18
+ 'Pass repo (e.g. "dain-agency/dain-os"), prNumber, and scoredBy (the caller\'s UUID). ' +
19
+ 'Returns an empty array when all findings are already scored. ' +
20
+ 'Returns a 404-style error when the PR has no reviews recorded.',
21
+ inputSchema: z.object({
22
+ repo: z
23
+ .string()
24
+ .min(1)
25
+ .describe('Full GitHub repo path, e.g. "dain-agency/dain-os".'),
26
+ prNumber: z.coerce
27
+ .number()
28
+ .int()
29
+ .positive()
30
+ .describe('The PR number, e.g. 307.'),
31
+ scoredBy: z
32
+ .string()
33
+ .uuid()
34
+ .describe('UUID of the user doing the scoring (used to exclude already-scored findings).'),
35
+ }),
36
+ handler: async (client, input) => {
37
+ const params = new URLSearchParams({
38
+ repo: input.repo,
39
+ prNumber: String(input.prNumber),
40
+ scoredBy: input.scoredBy,
41
+ });
42
+ return client.get(`/pr-review/findings/unscored?${params.toString()}`);
43
+ },
44
+ };
45
+ const scorePrFinding = {
46
+ name: 'score_pr_finding',
47
+ description: 'Record a verdict for a single DainOS-reviewer finding. ' +
48
+ 'Verdicts are "useful" (actionable, correctly identified), "noise" (not worth raising), ' +
49
+ 'or "wrong" (factually incorrect). "Skip" is not a valid verdict — only persist when a decision is made. ' +
50
+ 'Returns 201 with the created row on success. ' +
51
+ 'Returns 409 with the existing row when the same scorer has already scored this finding. ' +
52
+ 'Returns 404 when the findingId does not exist.',
53
+ inputSchema: z.object({
54
+ findingId: z
55
+ .string()
56
+ .uuid()
57
+ .describe('UUID of the pr_review_findings row to score.'),
58
+ verdict: verdictEnum.describe('One of "useful", "noise", or "wrong". Matches the DB CHECK constraint exactly.'),
59
+ scoredBy: z
60
+ .string()
61
+ .uuid()
62
+ .describe('UUID of the user recording this verdict.'),
63
+ notes: z
64
+ .string()
65
+ .max(2000)
66
+ .optional()
67
+ .describe('Optional free-text notes explaining the verdict.'),
68
+ reviewerVersion: z
69
+ .string()
70
+ .max(100)
71
+ .optional()
72
+ .describe('Reviewer version string at time of scoring, e.g. "v2.1".'),
73
+ }),
74
+ handler: async (client, input) => {
75
+ const { findingId, ...body } = input;
76
+ return client.post(`/pr-review/findings/${findingId}/feedback`, body);
77
+ },
78
+ };
79
+ export const prReviewTools = [
80
+ listUnscoredPrFindings,
81
+ scorePrFinding,
82
+ ];
83
+ //# sourceMappingURL=pr-review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pr-review.js","sourceRoot":"","sources":["../../src/tools/pr-review.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;;;;;;;GAUG;AAEH,2EAA2E;AAC3E,MAAM,WAAW,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;AAEzD,MAAM,sBAAsB,GAAmB;IAC7C,IAAI,EAAE,2BAA2B;IACjC,WAAW,EACT,8FAA8F;QAC9F,uFAAuF;QACvF,+DAA+D;QAC/D,gEAAgE;IAClE,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,CAAC;aACN,QAAQ,CAAC,oDAAoD,CAAC;QACjE,QAAQ,EAAE,CAAC,CAAC,MAAM;aACf,MAAM,EAAE;aACR,GAAG,EAAE;aACL,QAAQ,EAAE;aACV,QAAQ,CAAC,0BAA0B,CAAC;QACvC,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,IAAI,EAAE;aACN,QAAQ,CAAC,+EAA+E,CAAC;KAC7F,CAAC;IACF,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE;QAC/B,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;YACjC,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;YAChC,QAAQ,EAAE,KAAK,CAAC,QAAQ;SACzB,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,GAAG,CAAC,gCAAgC,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACzE,CAAC;CACF,CAAC;AAEF,MAAM,cAAc,GAAmB;IACrC,IAAI,EAAE,kBAAkB;IACxB,WAAW,EACT,yDAAyD;QACzD,yFAAyF;QACzF,0GAA0G;QAC1G,+CAA+C;QAC/C,0FAA0F;QAC1F,gDAAgD;IAClD,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,SAAS,EAAE,CAAC;aACT,MAAM,EAAE;aACR,IAAI,EAAE;aACN,QAAQ,CAAC,8CAA8C,CAAC;QAC3D,OAAO,EAAE,WAAW,CAAC,QAAQ,CAC3B,gFAAgF,CACjF;QACD,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,IAAI,EAAE;aACN,QAAQ,CAAC,0CAA0C,CAAC;QACvD,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,GAAG,CAAC,IAAI,CAAC;aACT,QAAQ,EAAE;aACV,QAAQ,CAAC,kDAAkD,CAAC;QAC/D,eAAe,EAAE,CAAC;aACf,MAAM,EAAE;aACR,GAAG,CAAC,GAAG,CAAC;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,0DAA0D,CAAC;KACxE,CAAC;IACF,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE;QAC/B,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAC;QACrC,OAAO,MAAM,CAAC,IAAI,CAAC,uBAAuB,SAAS,WAAW,EAAE,IAAI,CAAC,CAAC;IACxE,CAAC;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAqB;IAC7C,sBAAsB;IACtB,cAAc;CACf,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ToolDefinition } from './types.js';
2
+ export declare const productTools: ToolDefinition[];
3
+ //# sourceMappingURL=products.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"products.d.ts","sourceRoot":"","sources":["../../src/tools/products.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AA4CjD,eAAO,MAAM,YAAY,EAAE,cAAc,EAAgD,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Product tools. Two read operations: lookup_product_repos and summarise_product_tasks.
4
+ *
5
+ * These back /recap and /wrap-up so the skills can resolve a GitHub repo to a
6
+ * product without dropping to raw SQL.
7
+ */
8
+ // ---------------------------------------------------------------------------
9
+ // lookup_product_repos — find product(s) by GitHub owner + repo
10
+ // ---------------------------------------------------------------------------
11
+ const lookupProductRepos = {
12
+ name: 'lookup_product_repos',
13
+ description: 'Look up which DainOS product(s) are linked to a GitHub repository. Returns an array because a single repo can be linked to more than one product. Use this to resolve "which product does this repo belong to?" during /recap or /wrapup without raw SQL.',
14
+ inputSchema: z.object({
15
+ owner: z.string().min(1).describe('GitHub organisation or username, e.g. "dain-agency".'),
16
+ repo: z.string().min(1).describe('GitHub repository name, e.g. "dain-os".'),
17
+ }),
18
+ handler: async (client, input) => {
19
+ const params = new URLSearchParams();
20
+ params.set('owner', input.owner);
21
+ params.set('repo', input.repo);
22
+ return client.get(`/products/repos/lookup?${params.toString()}`);
23
+ },
24
+ };
25
+ // ---------------------------------------------------------------------------
26
+ // summarise_product_tasks — cross-project task aggregation for a product
27
+ // ---------------------------------------------------------------------------
28
+ const summariseProductTasks = {
29
+ name: 'summarise_product_tasks',
30
+ description: 'Get a task summary across all projects linked to a product. Returns status counts for all 8 statuses (backlog, todo, in_progress, review, production_ready, blocked, done, cancelled) — zeros included — plus up to 20 "active" tasks (in_progress, review, blocked, or done within the last 7 days). Use during /recap to give the user a live picture of where work stands.',
31
+ inputSchema: z.object({
32
+ productId: z.string().uuid().describe('The product UUID.'),
33
+ }),
34
+ handler: async (client, input) => client.get(`/products/${input.productId}/tasks/summary`),
35
+ };
36
+ export const productTools = [lookupProductRepos, summariseProductTasks];
37
+ //# sourceMappingURL=products.js.map