tavant-docs-mcp 1.0.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/assets/bg-agenda-data.jpeg +0 -0
- package/assets/bg-breaker-brain.jpeg +0 -0
- package/assets/bg-breaker-cloud.jpeg +0 -0
- package/assets/bg-breaker-lines.jpeg +0 -0
- package/assets/bg-thankyou.jpeg +0 -0
- package/assets/bg-title-tech.jpeg +0 -0
- package/assets/cr-image1.png +0 -0
- package/assets/decor-cubes.png +0 -0
- package/assets/footer-bar.png +0 -0
- package/assets/tavant-logo-orange.png +0 -0
- package/assets/tavant-logo-small.png +0 -0
- package/assets/tavant-logo-white-sm.png +0 -0
- package/assets/tavant-logo-white.png +0 -0
- package/assets/tavant-template.potx +0 -0
- package/brand.js +21 -0
- package/index.js +172 -0
- package/knowledge/tavant-company.md +181 -0
- package/knowledge/tavant-template.md +61 -0
- package/package.json +32 -0
- package/templates/contract/builders.js +317 -0
- package/templates/contract/register.js +213 -0
- package/templates/contract/sections.js +73 -0
- package/templates/cr/builders.js +286 -0
- package/templates/cr/register.js +189 -0
- package/templates/cr/sections.js +55 -0
- package/templates/msa/builders.js +480 -0
- package/templates/msa/register.js +185 -0
- package/templates/msa/sections.js +86 -0
- package/templates/nda/builders.js +277 -0
- package/templates/nda/register.js +185 -0
- package/templates/nda/sections.js +73 -0
- package/templates/pptx/builders.js +712 -0
- package/templates/pptx/layouts.js +168 -0
- package/templates/pptx/register.js +363 -0
- package/templates/sow/builders.js +294 -0
- package/templates/sow/register.js +183 -0
- package/templates/sow/sections.js +76 -0
- package/test-custom-slide.js +79 -0
- package/test-e2e.js +190 -0
- package/test-msa.js +48 -0
- package/test-nda-cr.js +88 -0
- package/test-pptx.js +93 -0
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
const {
|
|
2
|
+
Document, Packer, Paragraph, TextRun, HeadingLevel,
|
|
3
|
+
AlignmentType, BorderStyle, Table, TableRow, TableCell,
|
|
4
|
+
WidthType, PageBreak, Header, Footer, ImageRun,
|
|
5
|
+
TabStopType, TabStopPosition, UnderlineType,
|
|
6
|
+
} = require("docx");
|
|
7
|
+
const fs = require("fs");
|
|
8
|
+
const BRAND = require("../../brand");
|
|
9
|
+
|
|
10
|
+
const FONT = BRAND.font;
|
|
11
|
+
const ORANGE = BRAND.colors.orange;
|
|
12
|
+
|
|
13
|
+
// ─── Reusable paragraph helpers ────────────────────────────────────────
|
|
14
|
+
function heading(text, level = HeadingLevel.HEADING_1) {
|
|
15
|
+
return new Paragraph({
|
|
16
|
+
heading: level,
|
|
17
|
+
spacing: { before: 300, after: 150 },
|
|
18
|
+
children: [
|
|
19
|
+
new TextRun({
|
|
20
|
+
text,
|
|
21
|
+
bold: true,
|
|
22
|
+
font: FONT,
|
|
23
|
+
size: level === HeadingLevel.HEADING_1 ? 28 : 24,
|
|
24
|
+
color: ORANGE,
|
|
25
|
+
}),
|
|
26
|
+
],
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function bodyText(text, options = {}) {
|
|
31
|
+
return new Paragraph({
|
|
32
|
+
spacing: { after: 120 },
|
|
33
|
+
children: [
|
|
34
|
+
new TextRun({
|
|
35
|
+
text,
|
|
36
|
+
font: FONT,
|
|
37
|
+
size: 22,
|
|
38
|
+
color: "333333",
|
|
39
|
+
...options,
|
|
40
|
+
}),
|
|
41
|
+
],
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function bulletItem(text) {
|
|
46
|
+
return new Paragraph({
|
|
47
|
+
bullet: { level: 0 },
|
|
48
|
+
spacing: { after: 80 },
|
|
49
|
+
children: [
|
|
50
|
+
new TextRun({ text, font: FONT, size: 22, color: "333333" }),
|
|
51
|
+
],
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function emptyLine() {
|
|
56
|
+
return new Paragraph({ spacing: { after: 100 }, children: [] });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ─── Section builders ──────────────────────────────────────────────────
|
|
60
|
+
const sectionBuilders = {
|
|
61
|
+
cover_page(data) {
|
|
62
|
+
return [
|
|
63
|
+
emptyLine(),
|
|
64
|
+
emptyLine(),
|
|
65
|
+
emptyLine(),
|
|
66
|
+
new Paragraph({
|
|
67
|
+
alignment: AlignmentType.CENTER,
|
|
68
|
+
spacing: { after: 200 },
|
|
69
|
+
children: [
|
|
70
|
+
new TextRun({
|
|
71
|
+
text: BRAND.company.toUpperCase(),
|
|
72
|
+
bold: true,
|
|
73
|
+
font: FONT,
|
|
74
|
+
size: 48,
|
|
75
|
+
color: ORANGE,
|
|
76
|
+
}),
|
|
77
|
+
],
|
|
78
|
+
}),
|
|
79
|
+
emptyLine(),
|
|
80
|
+
new Paragraph({
|
|
81
|
+
alignment: AlignmentType.CENTER,
|
|
82
|
+
spacing: { after: 100 },
|
|
83
|
+
children: [
|
|
84
|
+
new TextRun({
|
|
85
|
+
text: data.contract_title || "Services Agreement",
|
|
86
|
+
bold: true,
|
|
87
|
+
font: FONT,
|
|
88
|
+
size: 36,
|
|
89
|
+
color: "333333",
|
|
90
|
+
}),
|
|
91
|
+
],
|
|
92
|
+
}),
|
|
93
|
+
emptyLine(),
|
|
94
|
+
new Paragraph({
|
|
95
|
+
alignment: AlignmentType.CENTER,
|
|
96
|
+
spacing: { after: 80 },
|
|
97
|
+
children: [
|
|
98
|
+
new TextRun({
|
|
99
|
+
text: `Between Tavant and ${data.client_name || "[Client Name]"}`,
|
|
100
|
+
font: FONT,
|
|
101
|
+
size: 24,
|
|
102
|
+
color: "666666",
|
|
103
|
+
}),
|
|
104
|
+
],
|
|
105
|
+
}),
|
|
106
|
+
new Paragraph({
|
|
107
|
+
alignment: AlignmentType.CENTER,
|
|
108
|
+
spacing: { after: 80 },
|
|
109
|
+
children: [
|
|
110
|
+
new TextRun({
|
|
111
|
+
text: `Effective Date: ${data.effective_date || "[Date]"}`,
|
|
112
|
+
font: FONT,
|
|
113
|
+
size: 22,
|
|
114
|
+
color: "666666",
|
|
115
|
+
}),
|
|
116
|
+
],
|
|
117
|
+
}),
|
|
118
|
+
data.contract_number
|
|
119
|
+
? new Paragraph({
|
|
120
|
+
alignment: AlignmentType.CENTER,
|
|
121
|
+
children: [
|
|
122
|
+
new TextRun({
|
|
123
|
+
text: `Contract #: ${data.contract_number}`,
|
|
124
|
+
font: FONT,
|
|
125
|
+
size: 22,
|
|
126
|
+
color: "666666",
|
|
127
|
+
}),
|
|
128
|
+
],
|
|
129
|
+
})
|
|
130
|
+
: emptyLine(),
|
|
131
|
+
emptyLine(),
|
|
132
|
+
new Paragraph({
|
|
133
|
+
alignment: AlignmentType.CENTER,
|
|
134
|
+
children: [
|
|
135
|
+
new TextRun({
|
|
136
|
+
text: BRAND.footer,
|
|
137
|
+
font: FONT,
|
|
138
|
+
size: 18,
|
|
139
|
+
color: "999999",
|
|
140
|
+
italics: true,
|
|
141
|
+
}),
|
|
142
|
+
],
|
|
143
|
+
}),
|
|
144
|
+
];
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
parties(data) {
|
|
148
|
+
return [
|
|
149
|
+
heading("1. PARTIES"),
|
|
150
|
+
bodyText(`This Agreement is entered into by and between:`),
|
|
151
|
+
emptyLine(),
|
|
152
|
+
bodyText(`Party A (Client):`, { bold: true }),
|
|
153
|
+
bodyText(data.client_name || "[Client Legal Name]"),
|
|
154
|
+
bodyText(data.client_address || "[Client Address]"),
|
|
155
|
+
data.client_contact ? bodyText(`Contact: ${data.client_contact}`) : emptyLine(),
|
|
156
|
+
emptyLine(),
|
|
157
|
+
bodyText(`Party B (Service Provider):`, { bold: true }),
|
|
158
|
+
bodyText(data.tavant_entity || "Tavant Technologies Inc."),
|
|
159
|
+
bodyText(data.tavant_address || "1900 McCarthy Blvd, Suite 200, Milpitas, CA 95035"),
|
|
160
|
+
];
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
scope_of_work(data) {
|
|
164
|
+
const paragraphs = [
|
|
165
|
+
heading("2. SCOPE OF WORK"),
|
|
166
|
+
bodyText("The Service Provider shall provide the following services:"),
|
|
167
|
+
emptyLine(),
|
|
168
|
+
];
|
|
169
|
+
if (data.services) {
|
|
170
|
+
if (Array.isArray(data.services)) {
|
|
171
|
+
data.services.forEach((s) => paragraphs.push(bulletItem(s)));
|
|
172
|
+
} else {
|
|
173
|
+
paragraphs.push(bodyText(data.services));
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (data.deliverables) {
|
|
177
|
+
paragraphs.push(emptyLine());
|
|
178
|
+
paragraphs.push(bodyText("Deliverables:", { bold: true }));
|
|
179
|
+
if (Array.isArray(data.deliverables)) {
|
|
180
|
+
data.deliverables.forEach((d) => paragraphs.push(bulletItem(d)));
|
|
181
|
+
} else {
|
|
182
|
+
paragraphs.push(bodyText(data.deliverables));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (data.exclusions) {
|
|
186
|
+
paragraphs.push(emptyLine());
|
|
187
|
+
paragraphs.push(bodyText("Exclusions:", { bold: true }));
|
|
188
|
+
if (Array.isArray(data.exclusions)) {
|
|
189
|
+
data.exclusions.forEach((e) => paragraphs.push(bulletItem(e)));
|
|
190
|
+
} else {
|
|
191
|
+
paragraphs.push(bodyText(data.exclusions));
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return paragraphs;
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
timeline(data) {
|
|
198
|
+
const paragraphs = [
|
|
199
|
+
heading("3. TIMELINE & MILESTONES"),
|
|
200
|
+
bodyText(`Start Date: ${data.start_date || "[Start Date]"}`),
|
|
201
|
+
bodyText(`End Date: ${data.end_date || "[End Date]"}`),
|
|
202
|
+
];
|
|
203
|
+
if (data.milestones && Array.isArray(data.milestones)) {
|
|
204
|
+
paragraphs.push(emptyLine());
|
|
205
|
+
paragraphs.push(bodyText("Key Milestones:", { bold: true }));
|
|
206
|
+
data.milestones.forEach((m) => {
|
|
207
|
+
const label = typeof m === "string" ? m : `${m.date || ""} — ${m.description || m.label || ""}`;
|
|
208
|
+
paragraphs.push(bulletItem(label));
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
return paragraphs;
|
|
212
|
+
},
|
|
213
|
+
|
|
214
|
+
commercial_terms(data) {
|
|
215
|
+
return [
|
|
216
|
+
heading("4. COMMERCIAL TERMS"),
|
|
217
|
+
bodyText(`Total Contract Value: ${data.currency || "USD"} ${data.total_value || "[Amount]"}`),
|
|
218
|
+
emptyLine(),
|
|
219
|
+
bodyText("Payment Schedule:", { bold: true }),
|
|
220
|
+
...(Array.isArray(data.payment_schedule)
|
|
221
|
+
? data.payment_schedule.map((p) => bulletItem(typeof p === "string" ? p : `${p.milestone || ""}: ${p.amount || ""}`))
|
|
222
|
+
: [bodyText(data.payment_schedule || "As per milestones")]),
|
|
223
|
+
emptyLine(),
|
|
224
|
+
bodyText(`Payment Terms: ${data.payment_terms || "Net 30 days from invoice date"}`),
|
|
225
|
+
];
|
|
226
|
+
},
|
|
227
|
+
|
|
228
|
+
confidentiality(data) {
|
|
229
|
+
return [
|
|
230
|
+
heading("5. CONFIDENTIALITY"),
|
|
231
|
+
bodyText(
|
|
232
|
+
`Both parties agree to maintain the confidentiality of all proprietary information exchanged during the term of this Agreement and for a period of ${data.confidentiality_period || "2 (two) years"} following termination.`
|
|
233
|
+
),
|
|
234
|
+
emptyLine(),
|
|
235
|
+
bodyText(
|
|
236
|
+
"Confidential Information includes but is not limited to: technical data, trade secrets, business plans, customer information, financial data, and any information marked as confidential."
|
|
237
|
+
),
|
|
238
|
+
];
|
|
239
|
+
},
|
|
240
|
+
|
|
241
|
+
ip_rights(data) {
|
|
242
|
+
return [
|
|
243
|
+
heading("6. INTELLECTUAL PROPERTY"),
|
|
244
|
+
bodyText(`IP Ownership: ${data.ip_ownership || "All deliverables created under this Agreement shall be owned by the Client upon full payment."}`),
|
|
245
|
+
emptyLine(),
|
|
246
|
+
bodyText(`License: ${data.license_type || "Tavant retains rights to its pre-existing IP and tools, granting Client a non-exclusive license for use within the project scope."}`),
|
|
247
|
+
];
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
termination(data) {
|
|
251
|
+
return [
|
|
252
|
+
heading("7. TERMINATION"),
|
|
253
|
+
bodyText(`Notice Period: ${data.notice_period || "30 days written notice"}`),
|
|
254
|
+
emptyLine(),
|
|
255
|
+
bodyText("This Agreement may be terminated under the following conditions:", { bold: true }),
|
|
256
|
+
...(Array.isArray(data.termination_conditions)
|
|
257
|
+
? data.termination_conditions.map((c) => bulletItem(c))
|
|
258
|
+
: [
|
|
259
|
+
bulletItem("Mutual written agreement of both parties"),
|
|
260
|
+
bulletItem("Material breach not cured within 30 days of written notice"),
|
|
261
|
+
bulletItem("Insolvency or bankruptcy of either party"),
|
|
262
|
+
]),
|
|
263
|
+
];
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
liability(data) {
|
|
267
|
+
return [
|
|
268
|
+
heading("8. LIABILITY & INDEMNIFICATION"),
|
|
269
|
+
bodyText(`Liability Cap: ${data.liability_cap || "Total liability shall not exceed the total contract value."}`),
|
|
270
|
+
emptyLine(),
|
|
271
|
+
bodyText(`Warranty Period: ${data.warranty_period || "90 days from acceptance of each deliverable."}`),
|
|
272
|
+
emptyLine(),
|
|
273
|
+
bodyText(
|
|
274
|
+
"Each party shall indemnify and hold harmless the other party against claims arising from negligence, willful misconduct, or breach of this Agreement."
|
|
275
|
+
),
|
|
276
|
+
];
|
|
277
|
+
},
|
|
278
|
+
|
|
279
|
+
general_provisions(data) {
|
|
280
|
+
return [
|
|
281
|
+
heading("9. GENERAL PROVISIONS"),
|
|
282
|
+
bodyText(`Governing Law: ${data.governing_law || "State of California, United States"}`),
|
|
283
|
+
bodyText(`Jurisdiction: ${data.jurisdiction || "Courts of Santa Clara County, California"}`),
|
|
284
|
+
bodyText(`Dispute Resolution: ${data.dispute_resolution || "Binding arbitration under ICC rules"}`),
|
|
285
|
+
emptyLine(),
|
|
286
|
+
bodyText("Force Majeure: Neither party shall be liable for delays caused by events beyond reasonable control, including natural disasters, war, pandemic, or government actions."),
|
|
287
|
+
emptyLine(),
|
|
288
|
+
bodyText("Amendments: Any modification to this Agreement must be made in writing and signed by authorized representatives of both parties."),
|
|
289
|
+
];
|
|
290
|
+
},
|
|
291
|
+
|
|
292
|
+
signatures(data) {
|
|
293
|
+
return [
|
|
294
|
+
heading("10. SIGNATURES"),
|
|
295
|
+
emptyLine(),
|
|
296
|
+
bodyText("IN WITNESS WHEREOF, the parties have executed this Agreement as of the Effective Date."),
|
|
297
|
+
emptyLine(),
|
|
298
|
+
emptyLine(),
|
|
299
|
+
bodyText("For and on behalf of Client:", { bold: true }),
|
|
300
|
+
emptyLine(),
|
|
301
|
+
bodyText("_________________________________"),
|
|
302
|
+
bodyText(`Name: ${data.client_signatory || "[Authorized Signatory]"}`),
|
|
303
|
+
bodyText(`Title: ${data.client_title || "[Title]"}`),
|
|
304
|
+
bodyText("Date: _______________"),
|
|
305
|
+
emptyLine(),
|
|
306
|
+
emptyLine(),
|
|
307
|
+
bodyText("For and on behalf of Tavant:", { bold: true }),
|
|
308
|
+
emptyLine(),
|
|
309
|
+
bodyText("_________________________________"),
|
|
310
|
+
bodyText(`Name: ${data.tavant_signatory || "[Authorized Signatory]"}`),
|
|
311
|
+
bodyText(`Title: ${data.tavant_title || "[Title]"}`),
|
|
312
|
+
bodyText("Date: _______________"),
|
|
313
|
+
];
|
|
314
|
+
},
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
module.exports = sectionBuilders;
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
const { Document, Packer, Header, Footer, Paragraph, TextRun, AlignmentType } = require("docx");
|
|
2
|
+
const { z } = require("zod");
|
|
3
|
+
const { v4: uuidv4 } = require("uuid");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
const SECTIONS = require("./sections");
|
|
7
|
+
const sectionBuilders = require("./builders");
|
|
8
|
+
const BRAND = require("../../brand");
|
|
9
|
+
|
|
10
|
+
const contracts = new Map();
|
|
11
|
+
|
|
12
|
+
function register(server) {
|
|
13
|
+
server.tool(
|
|
14
|
+
"contract_list_sections",
|
|
15
|
+
"List all available sections for Tavant contract documents with their fields",
|
|
16
|
+
{},
|
|
17
|
+
async () => ({
|
|
18
|
+
content: [{
|
|
19
|
+
type: "text",
|
|
20
|
+
text: JSON.stringify(Object.values(SECTIONS).map((s) => ({
|
|
21
|
+
id: s.id, name: s.name, description: s.description, fields: s.fields,
|
|
22
|
+
})), null, 2),
|
|
23
|
+
}],
|
|
24
|
+
})
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
server.tool(
|
|
28
|
+
"contract_create",
|
|
29
|
+
"Create a new Tavant contract document. Returns a contract_id. Use contract_add_section to build it, then contract_export to save as .docx",
|
|
30
|
+
{
|
|
31
|
+
contract_title: z.string().optional().describe("Contract title, e.g. 'Master Services Agreement'"),
|
|
32
|
+
client_name: z.string().optional().describe("Client company name"),
|
|
33
|
+
effective_date: z.string().optional().describe("Contract effective date"),
|
|
34
|
+
},
|
|
35
|
+
async ({ contract_title, client_name, effective_date }) => {
|
|
36
|
+
const id = uuidv4();
|
|
37
|
+
contracts.set(id, {
|
|
38
|
+
title: contract_title || "Services Agreement",
|
|
39
|
+
client_name: client_name || "[Client]",
|
|
40
|
+
effective_date: effective_date || "[Date]",
|
|
41
|
+
sections: [],
|
|
42
|
+
});
|
|
43
|
+
return {
|
|
44
|
+
content: [{
|
|
45
|
+
type: "text",
|
|
46
|
+
text: JSON.stringify({
|
|
47
|
+
contract_id: id,
|
|
48
|
+
title: contracts.get(id).title,
|
|
49
|
+
message: "Contract created. Use contract_add_section to add sections, then contract_export to save.",
|
|
50
|
+
}),
|
|
51
|
+
}],
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
server.tool(
|
|
57
|
+
"contract_add_section",
|
|
58
|
+
"Add a section to a contract document",
|
|
59
|
+
{
|
|
60
|
+
contract_id: z.string().describe("The contract ID from contract_create"),
|
|
61
|
+
section: z.string().describe(
|
|
62
|
+
"Section ID: cover_page, parties, scope_of_work, timeline, commercial_terms, confidentiality, ip_rights, termination, liability, general_provisions, signatures"
|
|
63
|
+
),
|
|
64
|
+
data: z.record(z.any()).describe(
|
|
65
|
+
"Section content data. Use contract_list_sections to see fields per section."
|
|
66
|
+
),
|
|
67
|
+
},
|
|
68
|
+
async ({ contract_id, section, data }) => {
|
|
69
|
+
const contract = contracts.get(contract_id);
|
|
70
|
+
if (!contract) {
|
|
71
|
+
return { content: [{ type: "text", text: "Error: Contract not found." }], isError: true };
|
|
72
|
+
}
|
|
73
|
+
const builder = sectionBuilders[section];
|
|
74
|
+
if (!builder) {
|
|
75
|
+
return {
|
|
76
|
+
content: [{ type: "text", text: `Error: Unknown section "${section}". Available: ${Object.keys(SECTIONS).join(", ")}` }],
|
|
77
|
+
isError: true,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
contract.sections.push({ section, data: data || {} });
|
|
81
|
+
return {
|
|
82
|
+
content: [{
|
|
83
|
+
type: "text",
|
|
84
|
+
text: JSON.stringify({
|
|
85
|
+
message: `Section added: ${section}`,
|
|
86
|
+
total_sections: contract.sections.length,
|
|
87
|
+
}),
|
|
88
|
+
}],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
server.tool(
|
|
94
|
+
"contract_export",
|
|
95
|
+
"Export contract as a .docx Word document",
|
|
96
|
+
{
|
|
97
|
+
contract_id: z.string().describe("The contract ID"),
|
|
98
|
+
output_path: z.string().optional().describe("Output file path. Defaults to ./output/<title>.docx"),
|
|
99
|
+
},
|
|
100
|
+
async ({ contract_id, output_path }) => {
|
|
101
|
+
const contract = contracts.get(contract_id);
|
|
102
|
+
if (!contract) {
|
|
103
|
+
return { content: [{ type: "text", text: "Error: Contract not found." }], isError: true };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Build all section paragraphs
|
|
107
|
+
const children = [];
|
|
108
|
+
for (const { section, data } of contract.sections) {
|
|
109
|
+
const builder = sectionBuilders[section];
|
|
110
|
+
if (builder) {
|
|
111
|
+
const paragraphs = builder({
|
|
112
|
+
...data,
|
|
113
|
+
client_name: data.client_name || contract.client_name,
|
|
114
|
+
effective_date: data.effective_date || contract.effective_date,
|
|
115
|
+
contract_title: data.contract_title || contract.title,
|
|
116
|
+
});
|
|
117
|
+
children.push(...paragraphs);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const doc = new Document({
|
|
122
|
+
creator: "Tavant",
|
|
123
|
+
title: contract.title,
|
|
124
|
+
description: `Contract: ${contract.title}`,
|
|
125
|
+
styles: {
|
|
126
|
+
default: {
|
|
127
|
+
document: {
|
|
128
|
+
run: { font: BRAND.font, size: 22, color: "333333" },
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
sections: [{
|
|
133
|
+
properties: {
|
|
134
|
+
page: {
|
|
135
|
+
margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 },
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
headers: {
|
|
139
|
+
default: new Header({
|
|
140
|
+
children: [
|
|
141
|
+
new Paragraph({
|
|
142
|
+
alignment: AlignmentType.RIGHT,
|
|
143
|
+
children: [
|
|
144
|
+
new TextRun({
|
|
145
|
+
text: BRAND.footer,
|
|
146
|
+
font: BRAND.font,
|
|
147
|
+
size: 16,
|
|
148
|
+
color: "999999",
|
|
149
|
+
italics: true,
|
|
150
|
+
}),
|
|
151
|
+
],
|
|
152
|
+
}),
|
|
153
|
+
],
|
|
154
|
+
}),
|
|
155
|
+
},
|
|
156
|
+
footers: {
|
|
157
|
+
default: new Footer({
|
|
158
|
+
children: [
|
|
159
|
+
new Paragraph({
|
|
160
|
+
alignment: AlignmentType.CENTER,
|
|
161
|
+
children: [
|
|
162
|
+
new TextRun({
|
|
163
|
+
text: `${contract.title} | ${contract.client_name} | ${BRAND.company}`,
|
|
164
|
+
font: BRAND.font,
|
|
165
|
+
size: 16,
|
|
166
|
+
color: "999999",
|
|
167
|
+
}),
|
|
168
|
+
],
|
|
169
|
+
}),
|
|
170
|
+
],
|
|
171
|
+
}),
|
|
172
|
+
},
|
|
173
|
+
children,
|
|
174
|
+
}],
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
const buffer = await Packer.toBuffer(doc);
|
|
178
|
+
|
|
179
|
+
const sanitized = (contract.title || "contract").replace(/[^a-zA-Z0-9_-]/g, "_").substring(0, 50);
|
|
180
|
+
const defaultDir = path.join(process.cwd(), "output");
|
|
181
|
+
if (!fs.existsSync(defaultDir)) fs.mkdirSync(defaultDir, { recursive: true });
|
|
182
|
+
const filePath = output_path || path.join(defaultDir, `${sanitized}.docx`);
|
|
183
|
+
const dir = path.dirname(filePath);
|
|
184
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
185
|
+
fs.writeFileSync(filePath, buffer);
|
|
186
|
+
|
|
187
|
+
return {
|
|
188
|
+
content: [{
|
|
189
|
+
type: "text",
|
|
190
|
+
text: JSON.stringify({
|
|
191
|
+
message: "Contract exported",
|
|
192
|
+
file_path: filePath,
|
|
193
|
+
total_sections: contract.sections.length,
|
|
194
|
+
}),
|
|
195
|
+
}],
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
server.tool(
|
|
201
|
+
"contract_delete",
|
|
202
|
+
"Delete a contract from memory",
|
|
203
|
+
{ contract_id: z.string().describe("The contract ID") },
|
|
204
|
+
async ({ contract_id }) => {
|
|
205
|
+
if (contracts.delete(contract_id)) {
|
|
206
|
+
return { content: [{ type: "text", text: "Contract deleted." }] };
|
|
207
|
+
}
|
|
208
|
+
return { content: [{ type: "text", text: "Not found." }], isError: true };
|
|
209
|
+
}
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
module.exports = { register };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// Contract template section definitions
|
|
2
|
+
// Each section defines a part of the contract document
|
|
3
|
+
|
|
4
|
+
const SECTIONS = {
|
|
5
|
+
cover_page: {
|
|
6
|
+
id: "cover_page",
|
|
7
|
+
name: "Cover Page",
|
|
8
|
+
description: "Contract title, parties, effective date, and Tavant branding",
|
|
9
|
+
fields: ["contract_title", "client_name", "effective_date", "contract_number"],
|
|
10
|
+
},
|
|
11
|
+
parties: {
|
|
12
|
+
id: "parties",
|
|
13
|
+
name: "Parties",
|
|
14
|
+
description: "Full legal names, addresses, and roles of contracting parties",
|
|
15
|
+
fields: ["client_name", "client_address", "client_contact", "tavant_entity", "tavant_address"],
|
|
16
|
+
},
|
|
17
|
+
scope_of_work: {
|
|
18
|
+
id: "scope_of_work",
|
|
19
|
+
name: "Scope of Work",
|
|
20
|
+
description: "Detailed description of services, deliverables, and exclusions",
|
|
21
|
+
fields: ["services", "deliverables", "exclusions"],
|
|
22
|
+
},
|
|
23
|
+
timeline: {
|
|
24
|
+
id: "timeline",
|
|
25
|
+
name: "Timeline & Milestones",
|
|
26
|
+
description: "Project phases, milestones, and delivery dates",
|
|
27
|
+
fields: ["start_date", "end_date", "milestones"],
|
|
28
|
+
},
|
|
29
|
+
commercial_terms: {
|
|
30
|
+
id: "commercial_terms",
|
|
31
|
+
name: "Commercial Terms",
|
|
32
|
+
description: "Pricing, payment schedule, invoicing terms",
|
|
33
|
+
fields: ["total_value", "currency", "payment_schedule", "payment_terms"],
|
|
34
|
+
},
|
|
35
|
+
confidentiality: {
|
|
36
|
+
id: "confidentiality",
|
|
37
|
+
name: "Confidentiality & NDA",
|
|
38
|
+
description: "Non-disclosure obligations and data protection terms",
|
|
39
|
+
fields: ["confidentiality_period"],
|
|
40
|
+
},
|
|
41
|
+
ip_rights: {
|
|
42
|
+
id: "ip_rights",
|
|
43
|
+
name: "Intellectual Property",
|
|
44
|
+
description: "IP ownership, licensing, and pre-existing IP provisions",
|
|
45
|
+
fields: ["ip_ownership", "license_type"],
|
|
46
|
+
},
|
|
47
|
+
termination: {
|
|
48
|
+
id: "termination",
|
|
49
|
+
name: "Termination",
|
|
50
|
+
description: "Termination conditions, notice period, and exit obligations",
|
|
51
|
+
fields: ["notice_period", "termination_conditions"],
|
|
52
|
+
},
|
|
53
|
+
liability: {
|
|
54
|
+
id: "liability",
|
|
55
|
+
name: "Liability & Indemnification",
|
|
56
|
+
description: "Liability caps, indemnification, and warranty terms",
|
|
57
|
+
fields: ["liability_cap", "warranty_period"],
|
|
58
|
+
},
|
|
59
|
+
general_provisions: {
|
|
60
|
+
id: "general_provisions",
|
|
61
|
+
name: "General Provisions",
|
|
62
|
+
description: "Governing law, dispute resolution, force majeure, amendments",
|
|
63
|
+
fields: ["governing_law", "jurisdiction", "dispute_resolution"],
|
|
64
|
+
},
|
|
65
|
+
signatures: {
|
|
66
|
+
id: "signatures",
|
|
67
|
+
name: "Signatures",
|
|
68
|
+
description: "Signature blocks for both parties",
|
|
69
|
+
fields: ["client_signatory", "client_title", "tavant_signatory", "tavant_title"],
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
module.exports = SECTIONS;
|