@dain-os/mcp-server 0.21.0 → 0.22.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 (59) hide show
  1. package/dist/index.js +0 -0
  2. package/dist/tools/generic.d.ts +20 -1
  3. package/dist/tools/generic.d.ts.map +1 -1
  4. package/dist/tools/generic.js +171 -31
  5. package/dist/tools/generic.js.map +1 -1
  6. package/dist/tools/registry.d.ts.map +1 -1
  7. package/dist/tools/registry.js +3 -1
  8. package/dist/tools/registry.js.map +1 -1
  9. package/dist/tools/semantic/tasks.js +1 -1
  10. package/dist/tools/semantic/tasks.js.map +1 -1
  11. package/package.json +1 -1
  12. package/dist/tools/cadence.d.ts +0 -4
  13. package/dist/tools/cadence.d.ts.map +0 -1
  14. package/dist/tools/cadence.js +0 -245
  15. package/dist/tools/cadence.js.map +0 -1
  16. package/dist/tools/comments.d.ts +0 -3
  17. package/dist/tools/comments.d.ts.map +0 -1
  18. package/dist/tools/comments.js +0 -19
  19. package/dist/tools/comments.js.map +0 -1
  20. package/dist/tools/developer.d.ts +0 -3
  21. package/dist/tools/developer.d.ts.map +0 -1
  22. package/dist/tools/developer.js +0 -349
  23. package/dist/tools/developer.js.map +0 -1
  24. package/dist/tools/iam.d.ts +0 -3
  25. package/dist/tools/iam.d.ts.map +0 -1
  26. package/dist/tools/iam.js +0 -38
  27. package/dist/tools/iam.js.map +0 -1
  28. package/dist/tools/log-time-entry.d.ts +0 -3
  29. package/dist/tools/log-time-entry.d.ts.map +0 -1
  30. package/dist/tools/log-time-entry.js +0 -54
  31. package/dist/tools/log-time-entry.js.map +0 -1
  32. package/dist/tools/pr-review.d.ts +0 -3
  33. package/dist/tools/pr-review.d.ts.map +0 -1
  34. package/dist/tools/pr-review.js +0 -83
  35. package/dist/tools/pr-review.js.map +0 -1
  36. package/dist/tools/products.d.ts +0 -3
  37. package/dist/tools/products.d.ts.map +0 -1
  38. package/dist/tools/products.js +0 -37
  39. package/dist/tools/products.js.map +0 -1
  40. package/dist/tools/projects.d.ts +0 -3
  41. package/dist/tools/projects.d.ts.map +0 -1
  42. package/dist/tools/projects.js +0 -151
  43. package/dist/tools/projects.js.map +0 -1
  44. package/dist/tools/proposal-content.d.ts +0 -3
  45. package/dist/tools/proposal-content.d.ts.map +0 -1
  46. package/dist/tools/proposal-content.js +0 -136
  47. package/dist/tools/proposal-content.js.map +0 -1
  48. package/dist/tools/proposal-options.d.ts +0 -3
  49. package/dist/tools/proposal-options.d.ts.map +0 -1
  50. package/dist/tools/proposal-options.js +0 -132
  51. package/dist/tools/proposal-options.js.map +0 -1
  52. package/dist/tools/proposals.d.ts +0 -22
  53. package/dist/tools/proposals.d.ts.map +0 -1
  54. package/dist/tools/proposals.js +0 -179
  55. package/dist/tools/proposals.js.map +0 -1
  56. package/dist/tools/tasks.d.ts +0 -3
  57. package/dist/tools/tasks.d.ts.map +0 -1
  58. package/dist/tools/tasks.js +0 -255
  59. package/dist/tools/tasks.js.map +0 -1
@@ -1,3 +0,0 @@
1
- import type { ToolDefinition } from './types.js';
2
- export declare const proposalOptionTools: ToolDefinition[];
3
- //# sourceMappingURL=proposal-options.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"proposal-options.d.ts","sourceRoot":"","sources":["../../src/tools/proposal-options.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AA6IjD,eAAO,MAAM,mBAAmB,EAAE,cAAc,EAM/C,CAAC"}
@@ -1,132 +0,0 @@
1
- import { z } from 'zod';
2
- /**
3
- * Proposal-options tools. Five operations: list, create, update, delete,
4
- * set_recommended.
5
- *
6
- * Pricing model semantics (mirrors the API's `applyPricingModelRefinement`):
7
- * - retainer -> monthlyAmount required
8
- * - fixed_fee -> oneTimeAmount required
9
- * - ad_hoc -> dayRate required
10
- * - blended -> oneTimeAmount AND dayRate required
11
- *
12
- * Only one option per proposal may be marked `recommended`. The API enforces
13
- * this atomically (partial UNIQUE index + sibling-clear inside one
14
- * transaction), so calling `set_recommended_option` will safely swap the
15
- * recommended flag from any previously-recommended option onto the target.
16
- */
17
- const pricingModelEnum = z.enum(['retainer', 'fixed_fee', 'ad_hoc', 'blended']);
18
- const baseOptionFields = z.object({
19
- title: z.string().min(1).max(255).describe('Display title for this option (e.g. "Retainer", "Fixed-fee build").'),
20
- description: z.string().max(10_000).nullable().optional(),
21
- pricingModel: pricingModelEnum,
22
- currencyId: z.string().uuid().nullable().optional(),
23
- monthlyAmount: z
24
- .number()
25
- .nonnegative()
26
- .nullable()
27
- .optional()
28
- .describe('Required when pricingModel is "retainer".'),
29
- oneTimeAmount: z
30
- .number()
31
- .nonnegative()
32
- .nullable()
33
- .optional()
34
- .describe('Required when pricingModel is "fixed_fee" or "blended".'),
35
- dayRate: z
36
- .number()
37
- .nonnegative()
38
- .nullable()
39
- .optional()
40
- .describe('Required when pricingModel is "ad_hoc" or "blended".'),
41
- discountPercentage: z.coerce.number().min(0).max(100).nullable().optional(),
42
- discountAmount: z.coerce.number().nonnegative().nullable().optional(),
43
- taxRate: z.coerce.number().min(0).max(100).nullable().optional(),
44
- taxAmount: z.coerce.number().nonnegative().nullable().optional(),
45
- termMonths: z.coerce.number().int().nonnegative().nullable().optional(),
46
- noticePeriodWeeks: z.coerce.number().int().nonnegative().nullable().optional(),
47
- recommended: z
48
- .boolean()
49
- .optional()
50
- .describe('Mark this option as the recommended one. At most one option per proposal can be recommended; the API atomically clears the previous recommendation when set.'),
51
- clauseSetKey: z
52
- .string()
53
- .min(1)
54
- .max(255)
55
- .describe('Identifier for the contract clause set this option will compose against on accept.'),
56
- servicesSchedule: z.string().nullable().optional(),
57
- });
58
- const listProposalOptions = {
59
- name: 'list_proposal_options',
60
- description: 'List the pricing options for a proposal, in display order. Each option carries its pricing-model-specific amounts, term, notice period, and a `recommended` flag (at most one option per proposal is recommended at a time).',
61
- inputSchema: z.object({
62
- proposalId: z.string().uuid(),
63
- }),
64
- handler: async (client, input) => client.get(`/crm/proposals/${input.proposalId}/options`),
65
- };
66
- const createProposalOption = {
67
- name: 'create_proposal_option',
68
- description: 'Create a new pricing option on a proposal. The new option is appended to the end of the existing options (display_order = max + 1). Pricing-model-specific amount fields are required: retainer needs monthlyAmount; fixed_fee needs oneTimeAmount; ad_hoc needs dayRate; blended needs both oneTimeAmount and dayRate. Setting `recommended: true` here will atomically clear the recommended flag on any other option of this proposal.',
69
- inputSchema: baseOptionFields.extend({
70
- proposalId: z.string().uuid(),
71
- }),
72
- handler: async (client, input) => {
73
- const { proposalId, ...body } = input;
74
- return client.post(`/crm/proposals/${proposalId}/options`, body);
75
- },
76
- };
77
- const updateProposalOption = {
78
- name: 'update_proposal_option',
79
- description: 'Update a proposal option. Pass any subset of fields; omitted fields are left unchanged. Pricing-model refinement still applies when `pricingModel` is sent (e.g. switching to retainer requires monthlyAmount). To mark this option as recommended, prefer `set_recommended_option` for clarity, though passing `recommended: true` here works too.',
80
- inputSchema: z.object({
81
- proposalId: z.string().uuid(),
82
- optionId: z.string().uuid(),
83
- title: z.string().min(1).max(255).optional(),
84
- description: z.string().max(10_000).nullable().optional(),
85
- pricingModel: pricingModelEnum.optional(),
86
- currencyId: z.string().uuid().nullable().optional(),
87
- monthlyAmount: z.coerce.number().nonnegative().nullable().optional(),
88
- oneTimeAmount: z.coerce.number().nonnegative().nullable().optional(),
89
- dayRate: z.coerce.number().nonnegative().nullable().optional(),
90
- discountPercentage: z.coerce.number().min(0).max(100).nullable().optional(),
91
- discountAmount: z.coerce.number().nonnegative().nullable().optional(),
92
- taxRate: z.coerce.number().min(0).max(100).nullable().optional(),
93
- taxAmount: z.coerce.number().nonnegative().nullable().optional(),
94
- termMonths: z.coerce.number().int().nonnegative().nullable().optional(),
95
- noticePeriodWeeks: z.coerce.number().int().nonnegative().nullable().optional(),
96
- recommended: z.boolean().optional(),
97
- clauseSetKey: z.string().min(1).max(255).optional(),
98
- servicesSchedule: z.string().nullable().optional(),
99
- }),
100
- handler: async (client, input) => {
101
- const { proposalId, optionId, ...body } = input;
102
- return client.patch(`/crm/proposals/${proposalId}/options/${optionId}`, body);
103
- },
104
- };
105
- const setRecommendedOption = {
106
- name: 'set_recommended_option',
107
- description: 'Mark one option as the recommended option on its proposal. Atomically clears the recommended flag from any other option of the same proposal. Use this in preference to `update_proposal_option` when the only change is the recommendation, to make the intent explicit.',
108
- inputSchema: z.object({
109
- proposalId: z.string().uuid(),
110
- optionId: z.string().uuid(),
111
- }),
112
- handler: async (client, input) => client.patch(`/crm/proposals/${input.proposalId}/options/${input.optionId}`, {
113
- recommended: true,
114
- }),
115
- };
116
- const deleteProposalOption = {
117
- name: 'delete_proposal_option',
118
- description: 'Delete a proposal option. Cascades to any line items scoped to that option. Display order on remaining options is left as-is; the API treats display_order as a sort key, not a contiguous sequence.',
119
- inputSchema: z.object({
120
- proposalId: z.string().uuid(),
121
- optionId: z.string().uuid(),
122
- }),
123
- handler: async (client, input) => client.delete(`/crm/proposals/${input.proposalId}/options/${input.optionId}`),
124
- };
125
- export const proposalOptionTools = [
126
- listProposalOptions,
127
- createProposalOption,
128
- updateProposalOption,
129
- setRecommendedOption,
130
- deleteProposalOption,
131
- ];
132
- //# sourceMappingURL=proposal-options.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"proposal-options.js","sourceRoot":"","sources":["../../src/tools/proposal-options.ts"],"names":[],"mappings":"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"}
@@ -1,22 +0,0 @@
1
- import type { ToolDefinition } from './types.js';
2
- /**
3
- * Coerce a proposal payload from the API into a shape that includes a
4
- * computed `shareUrl`. The API already returns `shareToken` -- we layer the
5
- * fully-qualified URL on top so the LLM never has to construct it from
6
- * fragments.
7
- */
8
- declare function addShareUrl<T extends Record<string, unknown>>(proposal: T): T & {
9
- shareUrl: string | null;
10
- };
11
- export declare const proposalTools: ToolDefinition[];
12
- /**
13
- * Exported for tests so they can assert on the computed shareUrl rule
14
- * without spinning up the full handler stack.
15
- */
16
- export declare const __testables: {
17
- addShareUrl: typeof addShareUrl;
18
- SHARE_URL_BASE: string;
19
- SHAREABLE_STATUSES: Set<string>;
20
- };
21
- export {};
22
- //# sourceMappingURL=proposals.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"proposals.d.ts","sourceRoot":"","sources":["../../src/tools/proposals.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AA4CjD;;;;;GAKG;AACH,iBAAS,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG;IAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAMpG;AA+HD,eAAO,MAAM,aAAa,EAAE,cAAc,EAOzC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,WAAW;;;;CAAsD,CAAC"}
@@ -1,179 +0,0 @@
1
- import { z } from 'zod';
2
- /**
3
- * Proposal tools. Six operations: list, get, create, update, delete, set_status.
4
- *
5
- * The DainOS proposal model has a structured "content" body (sections + blocks)
6
- * which is edited via the *content* tools in `proposal-content.ts` -- callers
7
- * should not POST the whole content blob via `update_proposal` for routine
8
- * edits. Use `update_proposal` for proposal-level fields (title, dates,
9
- * line items, links to deal/company/contact). Use the content tools for
10
- * sections + blocks.
11
- *
12
- * `get_proposal` includes a computed `shareUrl` when the proposal has been
13
- * sent (status one of: `sent`, `viewed`, `accepted`). For draft proposals
14
- * the field is `null` because the share link is not yet meaningful.
15
- */
16
- const PROPOSAL_STATUSES = [
17
- 'draft',
18
- 'sent',
19
- 'viewed',
20
- 'signed',
21
- 'accepted',
22
- 'rejected',
23
- 'expired',
24
- ];
25
- const SHAREABLE_STATUSES = new Set(['sent', 'viewed', 'signed', 'accepted']);
26
- const SHARE_URL_BASE = 'https://dainos.app/proposals/view';
27
- const proposalStatusEnum = z.enum(PROPOSAL_STATUSES);
28
- const lineItemSchema = z.object({
29
- name: z.string().min(1).max(255),
30
- description: z.string().nullable().optional(),
31
- quantity: z.coerce.number().positive(),
32
- unitType: z.string().min(1).max(50).optional().describe('e.g. "hour", "day", "unit". Defaults to "unit".'),
33
- unitPrice: z.coerce.number().nonnegative(),
34
- discountPercentage: z.coerce.number().min(0).max(100).nullable().optional(),
35
- isOptional: z.boolean().optional().describe('Optional line items do not contribute to the subtotal.'),
36
- sortOrder: z.coerce.number().int().optional(),
37
- });
38
- /**
39
- * Coerce a proposal payload from the API into a shape that includes a
40
- * computed `shareUrl`. The API already returns `shareToken` -- we layer the
41
- * fully-qualified URL on top so the LLM never has to construct it from
42
- * fragments.
43
- */
44
- function addShareUrl(proposal) {
45
- const status = proposal.status;
46
- const token = proposal.shareToken;
47
- const shareUrl = token && status && SHAREABLE_STATUSES.has(status) ? `${SHARE_URL_BASE}/${token}` : null;
48
- return { ...proposal, shareUrl };
49
- }
50
- function unwrap(response) {
51
- if (response && typeof response === 'object' && 'data' in response) {
52
- return response.data;
53
- }
54
- return response;
55
- }
56
- const listProposals = {
57
- name: 'list_proposals',
58
- description: 'List proposals in the current workspace. Returns id, title, status, totals, dates, and counterparty for each. Use this to discover proposal ids before calling get_proposal / get_proposal_content / update_proposal.',
59
- inputSchema: z.object({
60
- search: z.string().max(200).optional().describe('Free-text match against title.'),
61
- status: proposalStatusEnum.optional(),
62
- companyId: z.string().uuid().optional().describe('Filter by counterparty company.'),
63
- dealId: z.string().uuid().optional().describe('Filter by deal the proposal is attached to.'),
64
- }),
65
- handler: async (client, input) => {
66
- const params = new URLSearchParams();
67
- if (input.search)
68
- params.set('search', input.search);
69
- if (input.status)
70
- params.set('status', input.status);
71
- if (input.companyId)
72
- params.set('companyId', input.companyId);
73
- if (input.dealId)
74
- params.set('dealId', input.dealId);
75
- const query = params.toString() ? `?${params.toString()}` : '';
76
- return client.get(`/crm/proposals${query}`);
77
- },
78
- };
79
- const getProposal = {
80
- name: 'get_proposal',
81
- description: 'Get one proposal by id. Returns full proposal details including line items, options, counterparty, and a computed `shareUrl` (the public client viewing link) when the proposal has been sent. Draft proposals always return shareUrl=null.',
82
- inputSchema: z.object({
83
- id: z.string().uuid(),
84
- }),
85
- handler: async (client, input) => {
86
- const response = await client.get(`/crm/proposals/${input.id}`);
87
- const data = unwrap(response);
88
- if (data && typeof data === 'object') {
89
- return addShareUrl(data);
90
- }
91
- return data;
92
- },
93
- };
94
- const createProposal = {
95
- name: 'create_proposal',
96
- description: 'Create a new proposal. Only `title` is required. The new proposal is created with status=draft. Build the proposal content separately via the content tools (upsert_proposal_section + upsert_proposal_block) -- this endpoint accepts proposal-level fields only. Returns the created proposal with its id.',
97
- inputSchema: z.object({
98
- title: z.string().min(1).max(255),
99
- dealId: z.string().uuid().nullable().optional().describe('Link to a deal in the CRM pipeline.'),
100
- companyId: z.string().uuid().nullable().optional().describe('Counterparty company.'),
101
- contactId: z.string().uuid().nullable().optional().describe('Primary contact at the company.'),
102
- coverLetter: z.string().max(10000).nullable().optional(),
103
- termsAndConditions: z.string().max(10000).nullable().optional(),
104
- validFrom: z
105
- .string()
106
- .nullable()
107
- .optional()
108
- .describe('ISO 8601 date or datetime.'),
109
- validUntil: z
110
- .string()
111
- .nullable()
112
- .optional()
113
- .describe('ISO 8601 date or datetime.'),
114
- currencyId: z.string().uuid().nullable().optional(),
115
- lineItems: z.array(lineItemSchema).optional(),
116
- }),
117
- handler: async (client, input) => client.post('/crm/proposals', input),
118
- };
119
- const updateProposal = {
120
- name: 'update_proposal',
121
- description: 'Update an existing proposal. Pass any subset of proposal-level fields; omitted fields are left unchanged. Do NOT use this for content (sections + blocks) edits -- use upsert_proposal_section / upsert_proposal_block / etc. so you only send the bytes you are changing.',
122
- inputSchema: z.object({
123
- id: z.string().uuid(),
124
- title: z.string().min(1).max(255).optional(),
125
- dealId: z.string().uuid().nullable().optional(),
126
- companyId: z.string().uuid().nullable().optional(),
127
- contactId: z.string().uuid().nullable().optional(),
128
- coverLetter: z.string().max(10000).nullable().optional(),
129
- termsAndConditions: z.string().max(10000).nullable().optional(),
130
- validFrom: z.string().nullable().optional(),
131
- validUntil: z.string().nullable().optional(),
132
- currencyId: z.string().uuid().nullable().optional(),
133
- lineItems: z.array(lineItemSchema).optional(),
134
- }),
135
- handler: async (client, input) => {
136
- const { id, ...rest } = input;
137
- return client.put(`/crm/proposals/${id}`, rest);
138
- },
139
- };
140
- const setProposalStatus = {
141
- name: 'set_proposal_status',
142
- description: 'Update a proposal status. Transitioning to `sent` is what activates the client viewing link (shareUrl on get_proposal). `rejected` requires a `rejectionReason`.',
143
- inputSchema: z.object({
144
- id: z.string().uuid(),
145
- status: proposalStatusEnum,
146
- rejectionReason: z
147
- .string()
148
- .max(2000)
149
- .nullable()
150
- .optional()
151
- .describe('Required when status is `rejected`.'),
152
- }),
153
- handler: async (client, input) => {
154
- const { id, ...body } = input;
155
- return client.patch(`/crm/proposals/${id}/status`, body);
156
- },
157
- };
158
- const deleteProposal = {
159
- name: 'delete_proposal',
160
- description: 'Delete a proposal permanently. Returns 204 on success. Use cautiously -- there is no undelete. Prefer set_proposal_status to `expired` for proposals you want to retire while keeping the record.',
161
- inputSchema: z.object({
162
- id: z.string().uuid(),
163
- }),
164
- handler: async (client, input) => client.delete(`/crm/proposals/${input.id}`),
165
- };
166
- export const proposalTools = [
167
- listProposals,
168
- getProposal,
169
- createProposal,
170
- updateProposal,
171
- setProposalStatus,
172
- deleteProposal,
173
- ];
174
- /**
175
- * Exported for tests so they can assert on the computed shareUrl rule
176
- * without spinning up the full handler stack.
177
- */
178
- export const __testables = { addShareUrl, SHARE_URL_BASE, SHAREABLE_STATUSES };
179
- //# sourceMappingURL=proposals.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"proposals.js","sourceRoot":"","sources":["../../src/tools/proposals.ts"],"names":[],"mappings":"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"}
@@ -1,3 +0,0 @@
1
- import type { ToolDefinition } from './types.js';
2
- export declare const taskTools: ToolDefinition[];
3
- //# sourceMappingURL=tasks.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../../src/tools/tasks.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AA8RjD,eAAO,MAAM,SAAS,EAAE,cAAc,EAQrC,CAAC"}
@@ -1,255 +0,0 @@
1
- import { z } from 'zod';
2
- /**
3
- * Task tools. Six operations: list, get, create, update, complete, archive.
4
- *
5
- * `complete_task` is a thin wrapper around `update_task` with `status: "done"` —
6
- * but it makes the verb discoverable to the model, which matters more than DRY
7
- * here. The model will reach for it when the user says "mark this task done".
8
- */
9
- const taskStatusEnum = z.enum([
10
- 'backlog',
11
- 'todo',
12
- 'in_progress',
13
- 'in_review',
14
- 'blocked',
15
- 'done',
16
- 'cancelled',
17
- ]);
18
- const priorityMoscowEnum = z.enum(['must', 'should', 'could', 'wont']);
19
- const listTasks = {
20
- name: 'list_tasks',
21
- description: 'List tasks. All filters are optional. Common patterns: list_tasks({ projectId }) for one project, list_tasks({ assigneeId: "<me>" }) for the caller\'s work, list_tasks({ status: "in_progress" }) for active work.',
22
- inputSchema: z.object({
23
- projectId: z.string().uuid().optional().describe('Filter by project.'),
24
- assigneeId: z.string().uuid().optional().describe('Filter by assignee user id.'),
25
- status: taskStatusEnum.optional(),
26
- limit: z.coerce.number().int().min(1).max(100).optional().describe('Default 25, max 100.'),
27
- }),
28
- handler: async (client, input) => {
29
- const params = new URLSearchParams();
30
- if (input.projectId)
31
- params.set('projectId', input.projectId);
32
- if (input.assigneeId)
33
- params.set('assigneeId', input.assigneeId);
34
- if (input.status)
35
- params.set('status', input.status);
36
- if (input.limit !== undefined)
37
- params.set('limit', String(input.limit));
38
- const query = params.toString() ? `?${params.toString()}` : '';
39
- return client.get(`/tasks${query}`);
40
- },
41
- };
42
- const getTask = {
43
- name: 'get_task',
44
- description: 'Get one task by id. Returns the task plus assignee, dependencies, and comment count.',
45
- inputSchema: z.object({
46
- id: z.string().uuid(),
47
- }),
48
- handler: async (client, input) => client.get(`/tasks/${input.id}`),
49
- };
50
- /**
51
- * Resolve a fuzzy milestone name to a milestone id under the given project.
52
- * Case-insensitive substring match. Returns the id on a unique hit, throws
53
- * with an actionable message on zero or multiple matches so the model can
54
- * recover by calling list_milestones and picking an exact id.
55
- */
56
- async function resolveMilestoneName(client, projectId, rawName) {
57
- const needle = rawName.trim().toLowerCase();
58
- if (!needle) {
59
- throw new Error('milestoneName is empty after trimming. Pass a non-empty name or omit the field.');
60
- }
61
- const milestones = await client.get(`/projects/${projectId}/milestones`);
62
- const list = Array.isArray(milestones) ? milestones : [];
63
- const matches = list.filter((m) => m.name.toLowerCase().includes(needle));
64
- const [first] = matches;
65
- if (matches.length === 1 && first)
66
- return first.id;
67
- if (matches.length === 0) {
68
- const available = list.map((m) => `"${m.name}"`).join(', ') || '(none)';
69
- throw new Error(`No milestone matches "${rawName}" on project ${projectId}. Available: ${available}. Call list_milestones for ids, or omit milestoneName.`);
70
- }
71
- const names = matches.map((m) => `"${m.name}"`).join(', ');
72
- throw new Error(`"${rawName}" matches ${matches.length} milestones on project ${projectId}: ${names}. Pass a more specific milestoneName or use milestoneId directly.`);
73
- }
74
- const createTask = {
75
- name: 'create_task',
76
- description: 'Create a new task. `title` is required. When `projectId` is supplied you should ALMOST ALWAYS also pass `milestoneId` (preferred) or `milestoneName` (fuzzy-matched server-side); orphan tasks under a project with milestones clutter the project view. Use list_milestones first if you don\'t know the ids. The nested route is used automatically when projectId is set.',
77
- inputSchema: z.object({
78
- title: z.string().min(1).max(500),
79
- description: z.string().max(10000).optional(),
80
- projectId: z.string().uuid().optional(),
81
- milestoneId: z.string().uuid().optional(),
82
- milestoneName: z
83
- .string()
84
- .min(1)
85
- .max(200)
86
- .optional()
87
- .describe('Alternative to milestoneId. Case-insensitive substring match against the project\'s milestones. Requires projectId. Resolved server-side; fails fast on 0 or >1 matches with the candidate list so you can recover.'),
88
- parentTaskId: z.string().uuid().optional().describe('For subtasks.'),
89
- assigneeId: z.string().uuid().optional(),
90
- reporterId: z.string().uuid().optional(),
91
- status: taskStatusEnum.optional().describe('Defaults to backlog.'),
92
- priorityMoscow: priorityMoscowEnum.optional(),
93
- storyPoints: z.coerce.number().int().min(0).max(100).optional(),
94
- estimatedHours: z.coerce.number().min(0).optional(),
95
- dueDate: z.string().optional().describe('ISO 8601.'),
96
- startDate: z.string().optional().describe('ISO 8601.'),
97
- tags: z.array(z.string()).optional(),
98
- isBillable: z.boolean().optional(),
99
- }),
100
- handler: async (client, input) => {
101
- const { projectId, milestoneName, milestoneId, ...rest } = input;
102
- let resolvedMilestoneId = milestoneId;
103
- if (!resolvedMilestoneId && milestoneName) {
104
- if (!projectId) {
105
- throw new Error('milestoneName requires projectId. Pass projectId or use milestoneId directly.');
106
- }
107
- resolvedMilestoneId = await resolveMilestoneName(client, projectId, milestoneName);
108
- }
109
- const body = resolvedMilestoneId
110
- ? { ...rest, milestoneId: resolvedMilestoneId }
111
- : rest;
112
- if (projectId) {
113
- return client.post(`/projects/${projectId}/tasks`, body);
114
- }
115
- return client.post('/tasks', body);
116
- },
117
- };
118
- const updateTask = {
119
- name: 'update_task',
120
- description: 'Update a task. Pass any subset of fields. Covers internal content (title, description), client-view content (titleClient, descriptionClient), assignment to either an IAM user (assigneeId) or a portal user (portalAssigneeId), time logging (actualHoursDelta), and the clientViewLocked flag that protects hand-curated client copy from auto-regen. For just "mark done", prefer complete_task.',
121
- inputSchema: z.object({
122
- id: z.string().uuid(),
123
- title: z.string().min(1).max(500).optional(),
124
- description: z.string().max(10000).optional().describe('Plain-text description (internal).'),
125
- /** Client-friendly title. Falls back to `title` when null. Pair with descriptionClient for full client-view updates. */
126
- titleClient: z.string().max(500).nullable().optional(),
127
- descriptionClient: z.string().max(60000).nullable().optional().describe('Plain-text client-facing description.'),
128
- descriptionJson: z.array(z.unknown()).nullable().optional().describe('Plate JSON for the internal description editor.'),
129
- descriptionClientJson: z.array(z.unknown()).nullable().optional().describe('Plate JSON for the client-facing description editor.'),
130
- /** Locks the client view from auto-regeneration. True = `regenerate_client_view` will refuse without `force: true`. */
131
- clientViewLocked: z.boolean().optional(),
132
- status: taskStatusEnum.optional(),
133
- assigneeId: z.string().uuid().optional(),
134
- /** Portal-user assignee (client champion). Independent of `assigneeId`. */
135
- portalAssigneeId: z.string().uuid().nullable().optional(),
136
- priorityMoscow: priorityMoscowEnum.optional(),
137
- storyPoints: z.coerce.number().int().min(0).max(100).optional(),
138
- estimatedHours: z.coerce.number().min(0).optional(),
139
- actualHoursDelta: z.coerce.number().min(0).max(9999).optional().describe('Additive hours increment. actual_hours = actual_hours + delta. Use to log time without knowing the current total.'),
140
- milestoneId: z.string().uuid().nullable().optional().describe('Move the task to a different milestone (or detach with null). Call list_milestones first if you need ids.'),
141
- dueDate: z.string().optional().describe('ISO 8601.'),
142
- startDate: z.string().optional().describe('ISO 8601.'),
143
- completedAt: z
144
- .string()
145
- .refine((val) => !isNaN(Date.parse(val)), 'Invalid date')
146
- .nullable()
147
- .optional()
148
- .describe('ISO 8601. Override the completion timestamp. Auto-set when status changes to done.'),
149
- completedBy: z.string().uuid().nullable().optional().describe('IAM user UUID of the person who completed the task.'),
150
- tags: z.array(z.string()).optional(),
151
- }),
152
- handler: async (client, input) => {
153
- const { id, ...rest } = input;
154
- return client.put(`/tasks/${id}`, rest);
155
- },
156
- };
157
- /**
158
- * Triggers a server-side Anthropic rewrite of a task's internal title +
159
- * description into the jargon-free client-view variants (titleClient,
160
- * descriptionClient, descriptionClientJson). The model + prompt are owned
161
- * by the Express service so this tool is a thin call to
162
- * `POST /tasks/:id/regenerate-client-view`.
163
- *
164
- * Use after a /ship or /execute build round to keep the client portal copy
165
- * in sync without hand-editing. Refuses with 423 Locked when the task has
166
- * `clientViewLocked = true` unless `force: true` is set — locked tasks
167
- * carry hand-curated client copy (e.g. session recaps) that auto-regen
168
- * must not silently overwrite.
169
- */
170
- const regenerateClientView = {
171
- name: 'regenerate_client_view',
172
- description: 'Regenerate a task\'s client-view content (titleClient, descriptionClient, descriptionClientJson) from its current internal title and description. Uses an Anthropic call on the dain-api side. Returns the updated task. Refuses with 423 on locked tasks unless force: true.',
173
- inputSchema: z.object({
174
- id: z.string().uuid(),
175
- force: z
176
- .boolean()
177
- .optional()
178
- .describe('Override clientViewLocked. Only use after confirming with the user.'),
179
- // Allowlist mirrors the server-side schema and service guard. Keep this
180
- // list in sync with REGEN_ALLOWED_MODELS in apps/api tasks.service.ts.
181
- // If a caller passes anything else the server returns 400 INVALID_INPUT.
182
- model: z
183
- .enum(['claude-haiku-4-5-20251001', 'claude-sonnet-4-6'])
184
- .optional()
185
- .describe('Optional Anthropic model id. Defaults to Haiku 4.5 server-side. Only Haiku and Sonnet are allowed — Opus is rejected.'),
186
- }),
187
- handler: async (client, input) => {
188
- const { id, ...rest } = input;
189
- return client.post(`/tasks/${id}/regenerate-client-view`, rest);
190
- },
191
- };
192
- /**
193
- * The API enforces a task status state machine (see VALID_TASK_STATUS_TRANSITIONS
194
- * in apps/api). `backlog`, `todo`, `blocked`, and `cancelled` cannot transition
195
- * directly to `done` -- they must pass through `in_progress` first. Rather
196
- * than ask the caller to manage that, we read the current status and walk
197
- * through the minimum intermediate states. `in_progress` is the universal
198
- * predecessor: every state can either reach it directly or via one step
199
- * (`backlog -> todo -> in_progress`).
200
- */
201
- async function stepTaskToDone(client, taskId) {
202
- const path = `/tasks/${taskId}`;
203
- const current = (await client.get(path));
204
- const currentStatus = current.data?.status ??
205
- current.status;
206
- // No-op fast path.
207
- if (currentStatus === 'done')
208
- return current;
209
- // Minimum-hop paths to in_progress (the universal predecessor of done),
210
- // then to done.
211
- const pathToInProgress = {
212
- backlog: ['todo', 'in_progress'],
213
- todo: ['in_progress'],
214
- in_progress: [],
215
- review: [], // can transition directly to done
216
- production_ready: [], // can transition directly to done
217
- blocked: ['in_progress'],
218
- cancelled: ['backlog', 'todo', 'in_progress'],
219
- };
220
- const intermediates = currentStatus && currentStatus in pathToInProgress
221
- ? pathToInProgress[currentStatus]
222
- : [];
223
- // Walk through each intermediate state, then finally to done.
224
- let last = current;
225
- for (const step of intermediates ?? []) {
226
- last = await client.put(path, { status: step });
227
- }
228
- return client.put(path, { status: 'done' });
229
- }
230
- const completeTask = {
231
- name: 'complete_task',
232
- description: 'Mark a task as done. Handles the API\'s status state machine automatically: if the task is in `backlog`, `todo`, `blocked`, or `cancelled`, it walks through `in_progress` first (since the API rejects direct transitions from those states to `done`). Already-done tasks are returned as-is. Returns the final task.',
233
- inputSchema: z.object({
234
- id: z.string().uuid(),
235
- }),
236
- handler: async (client, input) => stepTaskToDone(client, input.id),
237
- };
238
- const archiveTask = {
239
- name: 'archive_task',
240
- description: 'Archive a task. Soft-deletes the task (status -> cancelled and removed from active queries). Use this when the task is no longer needed, not when it\'s complete.',
241
- inputSchema: z.object({
242
- id: z.string().uuid(),
243
- }),
244
- handler: async (client, input) => client.delete(`/tasks/${input.id}`),
245
- };
246
- export const taskTools = [
247
- listTasks,
248
- getTask,
249
- createTask,
250
- updateTask,
251
- completeTask,
252
- regenerateClientView,
253
- archiveTask,
254
- ];
255
- //# sourceMappingURL=tasks.js.map