@ttctl/mcp 0.0.0 → 0.1.0-rc.1
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/README.md +72 -9
- package/dist/auth.d.ts +40 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +69 -0
- package/dist/auth.js.map +1 -0
- package/dist/data-handling.d.ts +91 -0
- package/dist/data-handling.d.ts.map +1 -0
- package/dist/data-handling.js +129 -0
- package/dist/data-handling.js.map +1 -0
- package/dist/diagnostic.d.ts +262 -0
- package/dist/diagnostic.d.ts.map +1 -0
- package/dist/diagnostic.js +362 -0
- package/dist/diagnostic.js.map +1 -0
- package/dist/errors.d.ts +54 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +48 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/kill-switch-hook.d.ts +67 -0
- package/dist/kill-switch-hook.d.ts.map +1 -0
- package/dist/kill-switch-hook.js +61 -0
- package/dist/kill-switch-hook.js.map +1 -0
- package/dist/server.d.ts +100 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +157 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/_shared.d.ts +227 -0
- package/dist/tools/_shared.d.ts.map +1 -0
- package/dist/tools/_shared.js +238 -0
- package/dist/tools/_shared.js.map +1 -0
- package/dist/tools/applications.d.ts +27 -0
- package/dist/tools/applications.d.ts.map +1 -0
- package/dist/tools/applications.js +192 -0
- package/dist/tools/applications.js.map +1 -0
- package/dist/tools/availability.d.ts +33 -0
- package/dist/tools/availability.d.ts.map +1 -0
- package/dist/tools/availability.js +272 -0
- package/dist/tools/availability.js.map +1 -0
- package/dist/tools/contracts.d.ts +29 -0
- package/dist/tools/contracts.d.ts.map +1 -0
- package/dist/tools/contracts.js +157 -0
- package/dist/tools/contracts.js.map +1 -0
- package/dist/tools/engagements.d.ts +36 -0
- package/dist/tools/engagements.d.ts.map +1 -0
- package/dist/tools/engagements.js +408 -0
- package/dist/tools/engagements.js.map +1 -0
- package/dist/tools/file-upload.d.ts +133 -0
- package/dist/tools/file-upload.d.ts.map +1 -0
- package/dist/tools/file-upload.js +247 -0
- package/dist/tools/file-upload.js.map +1 -0
- package/dist/tools/index.d.ts +28 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +131 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/jobs.d.ts +37 -0
- package/dist/tools/jobs.d.ts.map +1 -0
- package/dist/tools/jobs.js +505 -0
- package/dist/tools/jobs.js.map +1 -0
- package/dist/tools/output-schemas.d.ts +115 -0
- package/dist/tools/output-schemas.d.ts.map +1 -0
- package/dist/tools/output-schemas.js +130 -0
- package/dist/tools/output-schemas.js.map +1 -0
- package/dist/tools/payments.d.ts +36 -0
- package/dist/tools/payments.d.ts.map +1 -0
- package/dist/tools/payments.js +373 -0
- package/dist/tools/payments.js.map +1 -0
- package/dist/tools/profile/certifications.d.ts +18 -0
- package/dist/tools/profile/certifications.d.ts.map +1 -0
- package/dist/tools/profile/certifications.js +193 -0
- package/dist/tools/profile/certifications.js.map +1 -0
- package/dist/tools/profile/education.d.ts +23 -0
- package/dist/tools/profile/education.d.ts.map +1 -0
- package/dist/tools/profile/education.js +196 -0
- package/dist/tools/profile/education.js.map +1 -0
- package/dist/tools/profile/employment.d.ts +23 -0
- package/dist/tools/profile/employment.d.ts.map +1 -0
- package/dist/tools/profile/employment.js +228 -0
- package/dist/tools/profile/employment.js.map +1 -0
- package/dist/tools/profile/industries.d.ts +22 -0
- package/dist/tools/profile/industries.d.ts.map +1 -0
- package/dist/tools/profile/industries.js +168 -0
- package/dist/tools/profile/industries.js.map +1 -0
- package/dist/tools/profile/portfolio.d.ts +22 -0
- package/dist/tools/profile/portfolio.d.ts.map +1 -0
- package/dist/tools/profile/portfolio.js +341 -0
- package/dist/tools/profile/portfolio.js.map +1 -0
- package/dist/tools/profile/resume.d.ts +16 -0
- package/dist/tools/profile/resume.d.ts.map +1 -0
- package/dist/tools/profile/resume.js +107 -0
- package/dist/tools/profile/resume.js.map +1 -0
- package/dist/tools/profile/shared.d.ts +85 -0
- package/dist/tools/profile/shared.d.ts.map +1 -0
- package/dist/tools/profile/shared.js +128 -0
- package/dist/tools/profile/shared.js.map +1 -0
- package/dist/tools/profile/visas.d.ts +15 -0
- package/dist/tools/profile/visas.d.ts.map +1 -0
- package/dist/tools/profile/visas.js +170 -0
- package/dist/tools/profile/visas.js.map +1 -0
- package/dist/tools/profile_basic_photo_show.d.ts +14 -0
- package/dist/tools/profile_basic_photo_show.d.ts.map +1 -0
- package/dist/tools/profile_basic_photo_show.js +59 -0
- package/dist/tools/profile_basic_photo_show.js.map +1 -0
- package/dist/tools/profile_basic_photo_upload.d.ts +24 -0
- package/dist/tools/profile_basic_photo_upload.d.ts.map +1 -0
- package/dist/tools/profile_basic_photo_upload.js +90 -0
- package/dist/tools/profile_basic_photo_upload.js.map +1 -0
- package/dist/tools/profile_basic_show.d.ts +19 -0
- package/dist/tools/profile_basic_show.d.ts.map +1 -0
- package/dist/tools/profile_basic_show.js +64 -0
- package/dist/tools/profile_basic_show.js.map +1 -0
- package/dist/tools/profile_basic_update.d.ts +37 -0
- package/dist/tools/profile_basic_update.d.ts.map +1 -0
- package/dist/tools/profile_basic_update.js +97 -0
- package/dist/tools/profile_basic_update.js.map +1 -0
- package/dist/tools/profile_external_advanced_wizard_show.d.ts +14 -0
- package/dist/tools/profile_external_advanced_wizard_show.d.ts.map +1 -0
- package/dist/tools/profile_external_advanced_wizard_show.js +56 -0
- package/dist/tools/profile_external_advanced_wizard_show.js.map +1 -0
- package/dist/tools/profile_external_custom_requirements_set.d.ts +13 -0
- package/dist/tools/profile_external_custom_requirements_set.d.ts.map +1 -0
- package/dist/tools/profile_external_custom_requirements_set.js +75 -0
- package/dist/tools/profile_external_custom_requirements_set.js.map +1 -0
- package/dist/tools/profile_external_custom_requirements_show.d.ts +14 -0
- package/dist/tools/profile_external_custom_requirements_show.d.ts.map +1 -0
- package/dist/tools/profile_external_custom_requirements_show.js +56 -0
- package/dist/tools/profile_external_custom_requirements_show.js.map +1 -0
- package/dist/tools/profile_external_readiness.d.ts +12 -0
- package/dist/tools/profile_external_readiness.d.ts.map +1 -0
- package/dist/tools/profile_external_readiness.js +54 -0
- package/dist/tools/profile_external_readiness.js.map +1 -0
- package/dist/tools/profile_external_recommendations.d.ts +15 -0
- package/dist/tools/profile_external_recommendations.d.ts.map +1 -0
- package/dist/tools/profile_external_recommendations.js +57 -0
- package/dist/tools/profile_external_recommendations.js.map +1 -0
- package/dist/tools/profile_external_update.d.ts +14 -0
- package/dist/tools/profile_external_update.d.ts.map +1 -0
- package/dist/tools/profile_external_update.js +79 -0
- package/dist/tools/profile_external_update.js.map +1 -0
- package/dist/tools/profile_reviews_approve_item.d.ts +17 -0
- package/dist/tools/profile_reviews_approve_item.d.ts.map +1 -0
- package/dist/tools/profile_reviews_approve_item.js +77 -0
- package/dist/tools/profile_reviews_approve_item.js.map +1 -0
- package/dist/tools/profile_reviews_approve_section.d.ts +15 -0
- package/dist/tools/profile_reviews_approve_section.d.ts.map +1 -0
- package/dist/tools/profile_reviews_approve_section.js +70 -0
- package/dist/tools/profile_reviews_approve_section.js.map +1 -0
- package/dist/tools/profile_reviews_list.d.ts +16 -0
- package/dist/tools/profile_reviews_list.d.ts.map +1 -0
- package/dist/tools/profile_reviews_list.js +58 -0
- package/dist/tools/profile_reviews_list.js.map +1 -0
- package/dist/tools/profile_reviews_submit_for_review.d.ts +14 -0
- package/dist/tools/profile_reviews_submit_for_review.d.ts.map +1 -0
- package/dist/tools/profile_reviews_submit_for_review.js +56 -0
- package/dist/tools/profile_reviews_submit_for_review.js.map +1 -0
- package/dist/tools/profile_skills_add.d.ts +4 -0
- package/dist/tools/profile_skills_add.d.ts.map +1 -0
- package/dist/tools/profile_skills_add.js +52 -0
- package/dist/tools/profile_skills_add.js.map +1 -0
- package/dist/tools/profile_skills_autocomplete.d.ts +4 -0
- package/dist/tools/profile_skills_autocomplete.d.ts.map +1 -0
- package/dist/tools/profile_skills_autocomplete.js +78 -0
- package/dist/tools/profile_skills_autocomplete.js.map +1 -0
- package/dist/tools/profile_skills_list.d.ts +16 -0
- package/dist/tools/profile_skills_list.d.ts.map +1 -0
- package/dist/tools/profile_skills_list.js +65 -0
- package/dist/tools/profile_skills_list.js.map +1 -0
- package/dist/tools/profile_skills_readiness.d.ts +4 -0
- package/dist/tools/profile_skills_readiness.d.ts.map +1 -0
- package/dist/tools/profile_skills_readiness.js +53 -0
- package/dist/tools/profile_skills_readiness.js.map +1 -0
- package/dist/tools/profile_skills_remove.d.ts +4 -0
- package/dist/tools/profile_skills_remove.d.ts.map +1 -0
- package/dist/tools/profile_skills_remove.js +53 -0
- package/dist/tools/profile_skills_remove.js.map +1 -0
- package/dist/tools/profile_skills_show.d.ts +4 -0
- package/dist/tools/profile_skills_show.d.ts.map +1 -0
- package/dist/tools/profile_skills_show.js +51 -0
- package/dist/tools/profile_skills_show.js.map +1 -0
- package/dist/tools/profile_skills_update.d.ts +11 -0
- package/dist/tools/profile_skills_update.d.ts.map +1 -0
- package/dist/tools/profile_skills_update.js +97 -0
- package/dist/tools/profile_skills_update.js.map +1 -0
- package/dist/tools/timesheet.d.ts +29 -0
- package/dist/tools/timesheet.d.ts.map +1 -0
- package/dist/tools/timesheet.js +257 -0
- package/dist/tools/timesheet.js.map +1 -0
- package/package.json +33 -13
- package/index.js +0 -7
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { profile } from "@ttctl/core";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { ttctlErrorToToolResponseOrNull } from "../../errors.js";
|
|
6
|
+
import { UPLOAD_CATEGORIES, decodeFileUploadInput, fileUploadInputSchema } from "../file-upload.js";
|
|
7
|
+
import { buildMcpDryRunPreview, dryRunResponse } from "../_shared.js";
|
|
8
|
+
const DRY_RUN_FIELD = z
|
|
9
|
+
.boolean()
|
|
10
|
+
.optional()
|
|
11
|
+
.describe("Preview the request without executing. Returns `{ ok: true, dryRun: true, preview }` with operationName + variables + redacted bearer header. Default: false.");
|
|
12
|
+
/**
|
|
13
|
+
* Register the eight `ttctl_profile_portfolio_*` MCP tools per the #75
|
|
14
|
+
* spec. Tool names use the canonical sub-domain `portfolio` (NOT the CLI
|
|
15
|
+
* alias `projects`) per project policy.
|
|
16
|
+
*
|
|
17
|
+
* Each tool maps 1:1 to a CLI leaf — the schemas describe the same set
|
|
18
|
+
* of fields, with file-upload tools accepting the dual `filePath` /
|
|
19
|
+
* `content` (base64) input per the spec.
|
|
20
|
+
*
|
|
21
|
+
* Dry-run path (issue #165): every tool accepts `dryRun?: boolean`. When
|
|
22
|
+
* `dryRun: true`, returns the uniform `{ ok: true, dryRun: true, preview }`
|
|
23
|
+
* envelope via MCP-layer preview building. For `upload_cover` /
|
|
24
|
+
* `upload_file`, the dry-run path emits the GraphQL operations envelope
|
|
25
|
+
* only (`file: null` placeholder) — the multipart binary body is NOT
|
|
26
|
+
* enumerated, mirroring the `profile.resume.upload` convention.
|
|
27
|
+
* `profileId` carries `DRY_RUN_PROFILE_ID_PLACEHOLDER` where the apply
|
|
28
|
+
* path resolves it via a sibling profile read.
|
|
29
|
+
*/
|
|
30
|
+
export function registerPortfolioTools(server, ctx) {
|
|
31
|
+
server.registerTool("ttctl_profile_portfolio_list", {
|
|
32
|
+
title: "List portfolio items",
|
|
33
|
+
description: "List the signed-in user's portfolio items (id, title, link, highlight, etc).",
|
|
34
|
+
inputSchema: { dryRun: DRY_RUN_FIELD },
|
|
35
|
+
}, async (args) => {
|
|
36
|
+
const auth = await ctx.resolveToolAuth();
|
|
37
|
+
if (!auth.ok)
|
|
38
|
+
return auth.response;
|
|
39
|
+
if (args.dryRun === true) {
|
|
40
|
+
return dryRunResponse(buildMcpDryRunPreview("getPortfolioItems", "talent-profile", { profileId: profile.basic.DRY_RUN_PROFILE_ID_PLACEHOLDER }, auth.token));
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
const items = await profile.portfolio.list(auth.token);
|
|
44
|
+
return successResponse(items);
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
return mapPortfolioError(err);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
server.registerTool("ttctl_profile_portfolio_add", {
|
|
51
|
+
title: "Create a portfolio item",
|
|
52
|
+
description: "Create a new portfolio item. `title` is required; other fields are optional. Use `ttctl_profile_portfolio_upload_cover` first if you want to attach a cover image, then pass the resulting `coverImageCacheName` via the `coverImage` field on a follow-up `update` call (or supply via the underlying GraphQL input — currently the cover-then-create flow is two-step).",
|
|
53
|
+
inputSchema: {
|
|
54
|
+
title: z.string().describe("Portfolio item title"),
|
|
55
|
+
description: z.string().optional().describe("Long-form description of the item"),
|
|
56
|
+
link: z.string().optional().describe("Primary URL for the item"),
|
|
57
|
+
websiteUrl: z.string().optional().describe("Public website URL associated with the item"),
|
|
58
|
+
accomplishment: z.string().optional().describe("Short accomplishment summary"),
|
|
59
|
+
clientOrCompanyName: z.string().optional().describe("Client or company name"),
|
|
60
|
+
publicationPermit: z.boolean().optional().describe("Whether the user has permission to publish this item"),
|
|
61
|
+
toptalRelated: z.boolean().optional().describe("Whether the work is Toptal-related"),
|
|
62
|
+
showViaToptal: z.boolean().optional().describe("Whether the item should be visible via Toptal"),
|
|
63
|
+
highlight: z.boolean().optional().describe("Whether to mark this item as a highlight"),
|
|
64
|
+
industryIds: z
|
|
65
|
+
.array(z.string())
|
|
66
|
+
.min(1)
|
|
67
|
+
.describe('Catalog Industry ids (at least one required). Discover via `ttctl_profile_industries_autocomplete` or `ttctl profile industries autocomplete "<query>"`.'),
|
|
68
|
+
dryRun: DRY_RUN_FIELD,
|
|
69
|
+
},
|
|
70
|
+
}, async (args) => {
|
|
71
|
+
const auth = await ctx.resolveToolAuth();
|
|
72
|
+
if (!auth.ok)
|
|
73
|
+
return auth.response;
|
|
74
|
+
const baseInput = buildPortfolioInput(args);
|
|
75
|
+
// industryIds is required by the schema (zod `.min(1)`); cast through
|
|
76
|
+
// the narrowed add-input type so the type-narrowed `add()` accepts it.
|
|
77
|
+
const input = { ...baseInput, industryIds: args.industryIds };
|
|
78
|
+
if (args.dryRun === true) {
|
|
79
|
+
return dryRunResponse(buildMcpDryRunPreview("createPortfolioItem", "talent-profile", { input: { profileId: profile.basic.DRY_RUN_PROFILE_ID_PLACEHOLDER, portfolioItem: input } }, auth.token));
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
const items = await profile.portfolio.add(auth.token, input);
|
|
83
|
+
return successResponse(items);
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
return mapPortfolioError(err);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
server.registerTool("ttctl_profile_portfolio_update", {
|
|
90
|
+
title: "Update a portfolio item",
|
|
91
|
+
description: "Update fields on an existing portfolio item by id. Only supplied fields are updated.",
|
|
92
|
+
inputSchema: {
|
|
93
|
+
id: z.string().describe("Id of the portfolio item to update"),
|
|
94
|
+
title: z.string().optional().describe("Portfolio item title"),
|
|
95
|
+
description: z.string().optional().describe("Long-form description of the item"),
|
|
96
|
+
link: z.string().optional().describe("Primary URL for the item"),
|
|
97
|
+
websiteUrl: z.string().optional().describe("Public website URL associated with the item"),
|
|
98
|
+
accomplishment: z.string().optional().describe("Short accomplishment summary"),
|
|
99
|
+
clientOrCompanyName: z.string().optional().describe("Client or company name"),
|
|
100
|
+
publicationPermit: z.boolean().optional().describe("Whether the user has permission to publish this item"),
|
|
101
|
+
toptalRelated: z.boolean().optional().describe("Whether the work is Toptal-related"),
|
|
102
|
+
showViaToptal: z.boolean().optional().describe("Whether the item should be visible via Toptal"),
|
|
103
|
+
highlight: z.boolean().optional().describe("Whether to mark this item as a highlight"),
|
|
104
|
+
industryIds: z
|
|
105
|
+
.array(z.string())
|
|
106
|
+
.min(1)
|
|
107
|
+
.optional()
|
|
108
|
+
.describe("Catalog Industry ids — when supplied, replaces the item's industry set (partial update)."),
|
|
109
|
+
dryRun: DRY_RUN_FIELD,
|
|
110
|
+
},
|
|
111
|
+
}, async (args) => {
|
|
112
|
+
const auth = await ctx.resolveToolAuth();
|
|
113
|
+
if (!auth.ok)
|
|
114
|
+
return auth.response;
|
|
115
|
+
const { id, ...rest } = args;
|
|
116
|
+
const changes = buildPortfolioInput(rest);
|
|
117
|
+
if (args.dryRun === true) {
|
|
118
|
+
return dryRunResponse(buildMcpDryRunPreview("updatePortfolioItem", "talent-profile", { input: { portfolioItemId: id, portfolioItem: changes } }, auth.token));
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
const items = await profile.portfolio.update(auth.token, id, changes);
|
|
122
|
+
return successResponse(items);
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
return mapPortfolioError(err);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
server.registerTool("ttctl_profile_portfolio_remove", {
|
|
129
|
+
title: "Remove a portfolio item",
|
|
130
|
+
description: "Remove a portfolio item by id.",
|
|
131
|
+
inputSchema: {
|
|
132
|
+
id: z.string().describe("Id of the portfolio item to remove"),
|
|
133
|
+
dryRun: DRY_RUN_FIELD,
|
|
134
|
+
},
|
|
135
|
+
}, async (args) => {
|
|
136
|
+
const auth = await ctx.resolveToolAuth();
|
|
137
|
+
if (!auth.ok)
|
|
138
|
+
return auth.response;
|
|
139
|
+
if (args.dryRun === true) {
|
|
140
|
+
return dryRunResponse(buildMcpDryRunPreview("removePortfolioItem", "talent-profile", { input: { portfolioItemId: args.id } }, auth.token));
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
const items = await profile.portfolio.remove(auth.token, args.id);
|
|
144
|
+
return successResponse(items);
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
return mapPortfolioError(err);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
server.registerTool("ttctl_profile_portfolio_reorder", {
|
|
151
|
+
title: "Reorder a portfolio item",
|
|
152
|
+
description: "Move a portfolio item to an absolute 0-based position. To compute relative-to-neighbour positions, list portfolio items first to find indices.",
|
|
153
|
+
inputSchema: {
|
|
154
|
+
id: z.string().describe("Id of the portfolio item to move"),
|
|
155
|
+
position: z.number().int().min(0).describe("Absolute 0-based position to move the item to"),
|
|
156
|
+
dryRun: DRY_RUN_FIELD,
|
|
157
|
+
},
|
|
158
|
+
}, async (args) => {
|
|
159
|
+
const auth = await ctx.resolveToolAuth();
|
|
160
|
+
if (!auth.ok)
|
|
161
|
+
return auth.response;
|
|
162
|
+
if (args.dryRun === true) {
|
|
163
|
+
return dryRunResponse(buildMcpDryRunPreview("changePortfolioItemPosition", "talent-profile", { input: { portfolioItemId: args.id, position: args.position } }, auth.token));
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
const items = await profile.portfolio.reorder(auth.token, args.id, args.position);
|
|
167
|
+
return successResponse(items);
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
return mapPortfolioError(err);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
server.registerTool("ttctl_profile_portfolio_highlight", {
|
|
174
|
+
title: "Toggle highlight on a portfolio item",
|
|
175
|
+
description: "Set or clear the `highlight` flag on a portfolio item.",
|
|
176
|
+
inputSchema: {
|
|
177
|
+
id: z.string().describe("Id of the portfolio item"),
|
|
178
|
+
highlight: z.boolean().default(true).describe("`true` to set highlight, `false` to clear"),
|
|
179
|
+
dryRun: DRY_RUN_FIELD,
|
|
180
|
+
},
|
|
181
|
+
}, async (args) => {
|
|
182
|
+
const auth = await ctx.resolveToolAuth();
|
|
183
|
+
if (!auth.ok)
|
|
184
|
+
return auth.response;
|
|
185
|
+
if (args.dryRun === true) {
|
|
186
|
+
return dryRunResponse(buildMcpDryRunPreview("highlightPortfolioItem", "talent-profile", { id: args.id, highlight: args.highlight }, auth.token));
|
|
187
|
+
}
|
|
188
|
+
try {
|
|
189
|
+
const result = await profile.portfolio.highlight(auth.token, args.id, args.highlight);
|
|
190
|
+
return successResponse(result);
|
|
191
|
+
}
|
|
192
|
+
catch (err) {
|
|
193
|
+
return mapPortfolioError(err);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
server.registerTool("ttctl_profile_portfolio_upload_cover", {
|
|
197
|
+
title: "Upload a portfolio cover image",
|
|
198
|
+
description: "Upload a cover image for the user's portfolio. Supply EITHER `filePath` (server-relative; preferred when the host has filesystem access — Claude Desktop, Claude Code) OR `content` (base64-encoded; for web-hosted clients without filesystem access). Returns `coverImageCacheName` and `coverImageUrl`; pass the cache name into a subsequent portfolio-add or portfolio-update call's `coverImage` field to bind the cover to a specific item. Server requires the image to be at least 750x500 px and under 5 MB.",
|
|
199
|
+
inputSchema: {
|
|
200
|
+
...fileUploadInputSchema,
|
|
201
|
+
cropX: z.number().int().nonnegative().optional().describe("crop origin x (px). Default: 0 (whole image)."),
|
|
202
|
+
cropY: z.number().int().nonnegative().optional().describe("crop origin y (px). Default: 0 (whole image)."),
|
|
203
|
+
cropW: z
|
|
204
|
+
.number()
|
|
205
|
+
.int()
|
|
206
|
+
.positive()
|
|
207
|
+
.optional()
|
|
208
|
+
.describe("crop width (px). Default: PNG image width if detectable, otherwise oversized (server clamps)."),
|
|
209
|
+
cropH: z
|
|
210
|
+
.number()
|
|
211
|
+
.int()
|
|
212
|
+
.positive()
|
|
213
|
+
.optional()
|
|
214
|
+
.describe("crop height (px). Default: PNG image height if detectable, otherwise oversized (server clamps)."),
|
|
215
|
+
dryRun: DRY_RUN_FIELD,
|
|
216
|
+
},
|
|
217
|
+
}, async (args) => {
|
|
218
|
+
const auth = await ctx.resolveToolAuth();
|
|
219
|
+
if (!auth.ok)
|
|
220
|
+
return auth.response;
|
|
221
|
+
if (args.dryRun === true) {
|
|
222
|
+
return dryRunResponse(buildMcpDryRunPreview("uploadPortfolioCover", "talent-profile", { profileId: profile.basic.DRY_RUN_PROFILE_ID_PLACEHOLDER, transformation: null, file: null }, auth.token));
|
|
223
|
+
}
|
|
224
|
+
const decoded = decodeFileUploadInput(args, UPLOAD_CATEGORIES.portfolioCover);
|
|
225
|
+
if ("isError" in decoded)
|
|
226
|
+
return decoded;
|
|
227
|
+
// Build the transformation only when ALL four crop fields are
|
|
228
|
+
// supplied; the service auto-defaults when omitted.
|
|
229
|
+
const transformation = args.cropX !== undefined && args.cropY !== undefined && args.cropW !== undefined && args.cropH !== undefined
|
|
230
|
+
? { cropX: args.cropX, cropY: args.cropY, cropW: args.cropW, cropH: args.cropH }
|
|
231
|
+
: undefined;
|
|
232
|
+
try {
|
|
233
|
+
const result = await profile.portfolio.uploadCover(auth.token, decoded, transformation);
|
|
234
|
+
return successResponse(result);
|
|
235
|
+
}
|
|
236
|
+
catch (err) {
|
|
237
|
+
return mapPortfolioError(err);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
server.registerTool("ttctl_profile_portfolio_upload_file", {
|
|
241
|
+
title: "Upload a portfolio attachment file",
|
|
242
|
+
description: "Upload an arbitrary attachment file for the user's portfolio. Supply EITHER `filePath` (preferred when the host has filesystem access) OR `content` (base64). Returns `fileCacheName` and `fileUrl`.",
|
|
243
|
+
inputSchema: { ...fileUploadInputSchema, dryRun: DRY_RUN_FIELD },
|
|
244
|
+
}, async (args) => {
|
|
245
|
+
const auth = await ctx.resolveToolAuth();
|
|
246
|
+
if (!auth.ok)
|
|
247
|
+
return auth.response;
|
|
248
|
+
if (args.dryRun === true) {
|
|
249
|
+
return dryRunResponse(buildMcpDryRunPreview("uploadPortfolioFile", "talent-profile", { profileId: profile.basic.DRY_RUN_PROFILE_ID_PLACEHOLDER, file: null }, auth.token));
|
|
250
|
+
}
|
|
251
|
+
const decoded = decodeFileUploadInput(args, UPLOAD_CATEGORIES.portfolioFile);
|
|
252
|
+
if ("isError" in decoded)
|
|
253
|
+
return decoded;
|
|
254
|
+
try {
|
|
255
|
+
const result = await profile.portfolio.uploadFile(auth.token, decoded);
|
|
256
|
+
return successResponse(result);
|
|
257
|
+
}
|
|
258
|
+
catch (err) {
|
|
259
|
+
return mapPortfolioError(err);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
function successResponse(data) {
|
|
264
|
+
return {
|
|
265
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Filter `undefined` values out of the optional-fields map so the
|
|
270
|
+
* resulting `PortfolioItemInput` satisfies `exactOptionalPropertyTypes`
|
|
271
|
+
* (which rejects `string | undefined` where `string` is expected).
|
|
272
|
+
*
|
|
273
|
+
* Zod's optional fields surface as `T | undefined` at the inferred type
|
|
274
|
+
* level; the service layer uses pure-optional `T?` keys. This helper
|
|
275
|
+
* bridges the two.
|
|
276
|
+
*/
|
|
277
|
+
function buildPortfolioInput(args) {
|
|
278
|
+
const out = {};
|
|
279
|
+
if (args.title !== undefined)
|
|
280
|
+
out.title = args.title;
|
|
281
|
+
if (args.description !== undefined)
|
|
282
|
+
out.description = args.description;
|
|
283
|
+
if (args.link !== undefined)
|
|
284
|
+
out.link = args.link;
|
|
285
|
+
if (args.websiteUrl !== undefined)
|
|
286
|
+
out.websiteUrl = args.websiteUrl;
|
|
287
|
+
if (args.accomplishment !== undefined)
|
|
288
|
+
out.accomplishment = args.accomplishment;
|
|
289
|
+
if (args.clientOrCompanyName !== undefined)
|
|
290
|
+
out.clientOrCompanyName = args.clientOrCompanyName;
|
|
291
|
+
if (args.publicationPermit !== undefined)
|
|
292
|
+
out.publicationPermit = args.publicationPermit;
|
|
293
|
+
if (args.toptalRelated !== undefined)
|
|
294
|
+
out.toptalRelated = args.toptalRelated;
|
|
295
|
+
if (args.showViaToptal !== undefined)
|
|
296
|
+
out.showViaToptal = args.showViaToptal;
|
|
297
|
+
if (args.highlight !== undefined)
|
|
298
|
+
out.highlight = args.highlight;
|
|
299
|
+
if (args.industryIds !== undefined)
|
|
300
|
+
out.industryIds = args.industryIds;
|
|
301
|
+
return out;
|
|
302
|
+
}
|
|
303
|
+
function mapPortfolioError(err) {
|
|
304
|
+
const typed = ttctlErrorToToolResponseOrNull(err);
|
|
305
|
+
if (typed !== null)
|
|
306
|
+
return typed;
|
|
307
|
+
if (err instanceof profile.portfolio.PortfolioError) {
|
|
308
|
+
return {
|
|
309
|
+
isError: true,
|
|
310
|
+
content: [
|
|
311
|
+
{
|
|
312
|
+
type: "text",
|
|
313
|
+
text: [
|
|
314
|
+
`Error: ${err.message}`,
|
|
315
|
+
"",
|
|
316
|
+
"Recovery: Adjust the tool input or retry; see the code below.",
|
|
317
|
+
"",
|
|
318
|
+
`(Code: ${err.code})`,
|
|
319
|
+
].join("\n"),
|
|
320
|
+
},
|
|
321
|
+
],
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
325
|
+
return {
|
|
326
|
+
isError: true,
|
|
327
|
+
content: [
|
|
328
|
+
{
|
|
329
|
+
type: "text",
|
|
330
|
+
text: [
|
|
331
|
+
`Error: portfolio request failed: ${message}`,
|
|
332
|
+
"",
|
|
333
|
+
"Recovery: Retry; if the failure persists, file an issue.",
|
|
334
|
+
"",
|
|
335
|
+
"(Code: UNKNOWN)",
|
|
336
|
+
].join("\n"),
|
|
337
|
+
},
|
|
338
|
+
],
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
//# sourceMappingURL=portfolio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portfolio.js","sourceRoot":"","sources":["../../../src/tools/profile/portfolio.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { type ToolRegistrationContext } from "../_shared.js";
|
|
3
|
+
/**
|
|
4
|
+
* Register the two `ttctl_profile_resume_*` MCP tools.
|
|
5
|
+
*
|
|
6
|
+
* Tool names use the canonical sub-domain `resume` (NOT the CLI alias
|
|
7
|
+
* `cv`) per project policy.
|
|
8
|
+
*
|
|
9
|
+
* Dry-run path (issue #165): both tools accept `dryRun?: boolean`. On
|
|
10
|
+
* `dryRun: true` they return the uniform `{ ok, dryRun, preview }`
|
|
11
|
+
* envelope describing the GraphQL operations envelope (multipart binary
|
|
12
|
+
* body is not enumerated for `upload` — only the operations envelope
|
|
13
|
+
* with `input.file = null` per the wire shape that core sends).
|
|
14
|
+
*/
|
|
15
|
+
export declare function registerResumeTools(server: McpServer, ctx: ToolRegistrationContext): void;
|
|
16
|
+
//# sourceMappingURL=resume.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resume.d.ts","sourceRoot":"","sources":["../../../src/tools/profile/resume.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMzE,OAAO,EAAuD,KAAK,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAUlH;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,uBAAuB,GAAG,IAAI,CAmDzF"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { profile } from "@ttctl/core";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { ttctlErrorToToolResponseOrNull } from "../../errors.js";
|
|
6
|
+
import { UPLOAD_CATEGORIES, decodeFileUploadInput, fileUploadInputSchema } from "../file-upload.js";
|
|
7
|
+
import { buildMcpDryRunPreview, dryRunResponse, jsonResponse } from "../_shared.js";
|
|
8
|
+
import { profileResumeUploadOutputSchema } from "../output-schemas.js";
|
|
9
|
+
const DRY_RUN_FIELD = z
|
|
10
|
+
.boolean()
|
|
11
|
+
.optional()
|
|
12
|
+
.describe("Preview the request without executing. Returns `{ ok: true, dryRun: true, preview }` with operationName + variables + redacted bearer header. Default: false.");
|
|
13
|
+
/**
|
|
14
|
+
* Register the two `ttctl_profile_resume_*` MCP tools.
|
|
15
|
+
*
|
|
16
|
+
* Tool names use the canonical sub-domain `resume` (NOT the CLI alias
|
|
17
|
+
* `cv`) per project policy.
|
|
18
|
+
*
|
|
19
|
+
* Dry-run path (issue #165): both tools accept `dryRun?: boolean`. On
|
|
20
|
+
* `dryRun: true` they return the uniform `{ ok, dryRun, preview }`
|
|
21
|
+
* envelope describing the GraphQL operations envelope (multipart binary
|
|
22
|
+
* body is not enumerated for `upload` — only the operations envelope
|
|
23
|
+
* with `input.file = null` per the wire shape that core sends).
|
|
24
|
+
*/
|
|
25
|
+
export function registerResumeTools(server, ctx) {
|
|
26
|
+
server.registerTool("ttctl_profile_resume_upload", {
|
|
27
|
+
title: "Upload a resume file",
|
|
28
|
+
description: "Upload the user's resume (PDF or DOCX). Supply EITHER `filePath` (server-relative; preferred when the host has filesystem access — Claude Desktop, Claude Code) OR `content` (base64-encoded; for web-hosted clients without filesystem access). Returns `{ success: true }` on a server-confirmed success. Pass `dryRun: true` to preview the GraphQL operations envelope without firing.",
|
|
29
|
+
inputSchema: { ...fileUploadInputSchema, dryRun: DRY_RUN_FIELD },
|
|
30
|
+
outputSchema: profileResumeUploadOutputSchema.shape,
|
|
31
|
+
}, async (args) => {
|
|
32
|
+
const auth = await ctx.resolveToolAuth();
|
|
33
|
+
if (!auth.ok)
|
|
34
|
+
return auth.response;
|
|
35
|
+
if (args.dryRun === true) {
|
|
36
|
+
return dryRunResponse(buildMcpDryRunPreview("uploadResume", "talent-profile", { input: { file: null } }, auth.token));
|
|
37
|
+
}
|
|
38
|
+
const decoded = decodeFileUploadInput(args, UPLOAD_CATEGORIES.resume);
|
|
39
|
+
if ("isError" in decoded)
|
|
40
|
+
return decoded;
|
|
41
|
+
try {
|
|
42
|
+
const result = await profile.resume.upload(auth.token, decoded);
|
|
43
|
+
return jsonResponse(result);
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
return mapResumeError(err);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
server.registerTool("ttctl_profile_resume_cancel_upload", {
|
|
50
|
+
title: "Cancel an in-flight resume upload",
|
|
51
|
+
description: "Cancel any in-flight resume upload, clearing half-uploaded server-side state. Idempotent — returns success even when no upload is in flight. Pass `dryRun: true` to preview the request without firing.",
|
|
52
|
+
inputSchema: { dryRun: DRY_RUN_FIELD },
|
|
53
|
+
}, async (args) => {
|
|
54
|
+
const auth = await ctx.resolveToolAuth();
|
|
55
|
+
if (!auth.ok)
|
|
56
|
+
return auth.response;
|
|
57
|
+
if (args.dryRun === true) {
|
|
58
|
+
return dryRunResponse(buildMcpDryRunPreview("cancelResumeUpload", "talent-profile", { input: {} }, auth.token));
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
const result = await profile.resume.cancelUpload(auth.token);
|
|
62
|
+
return jsonResponse(result);
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
return mapResumeError(err);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
function mapResumeError(err) {
|
|
70
|
+
const typed = ttctlErrorToToolResponseOrNull(err);
|
|
71
|
+
if (typed !== null)
|
|
72
|
+
return typed;
|
|
73
|
+
if (err instanceof profile.resume.ResumeError) {
|
|
74
|
+
return {
|
|
75
|
+
isError: true,
|
|
76
|
+
content: [
|
|
77
|
+
{
|
|
78
|
+
type: "text",
|
|
79
|
+
text: [
|
|
80
|
+
`Error: ${err.message}`,
|
|
81
|
+
"",
|
|
82
|
+
"Recovery: Adjust the tool input or retry; see the code below.",
|
|
83
|
+
"",
|
|
84
|
+
`(Code: ${err.code})`,
|
|
85
|
+
].join("\n"),
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
91
|
+
return {
|
|
92
|
+
isError: true,
|
|
93
|
+
content: [
|
|
94
|
+
{
|
|
95
|
+
type: "text",
|
|
96
|
+
text: [
|
|
97
|
+
`Error: resume request failed: ${message}`,
|
|
98
|
+
"",
|
|
99
|
+
"Recovery: Retry; if the failure persists, file an issue.",
|
|
100
|
+
"",
|
|
101
|
+
"(Code: UNKNOWN)",
|
|
102
|
+
].join("\n"),
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=resume.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resume.js","sourceRoot":"","sources":["../../../src/tools/profile/resume.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { ToolErrorResponse } from "../../errors.js";
|
|
3
|
+
/**
|
|
4
|
+
* Zod schema for sub-domain `--from` / `--to` / `--issued` / `--expires` /
|
|
5
|
+
* other date-flavored flags. Accepts ISO-8601 (`YYYY-MM-DD`) or year-only
|
|
6
|
+
* (`YYYY`); semantic validation (real calendar dates, year range) happens
|
|
7
|
+
* later inside `parseDateInput` from `@ttctl/core`. Hoisted here so the
|
|
8
|
+
* four sub-domain tool files share a single source of truth.
|
|
9
|
+
*/
|
|
10
|
+
export declare const dateInput: z.ZodString;
|
|
11
|
+
/**
|
|
12
|
+
* MCP tool-result success shape. Mirrors the SDK-side `CallToolResult`
|
|
13
|
+
* (which is inferred from a `z.core.$loose` schema and therefore carries
|
|
14
|
+
* an `[x: string]: unknown` index signature) — kept loose so the helper
|
|
15
|
+
* return type composes cleanly with the SDK's `ToolCallback`.
|
|
16
|
+
*
|
|
17
|
+
* `structuredContent` is populated by {@link jsonSuccess} so tools that
|
|
18
|
+
* declare an `outputSchema` (#226) get SDK-validated structured payload
|
|
19
|
+
* alongside the `text` slot.
|
|
20
|
+
*/
|
|
21
|
+
export interface ToolSuccessResponse {
|
|
22
|
+
[x: string]: unknown;
|
|
23
|
+
content: [{
|
|
24
|
+
type: "text";
|
|
25
|
+
text: string;
|
|
26
|
+
}];
|
|
27
|
+
structuredContent?: Record<string, unknown>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Render a JSON-serialized success response. Tools return structured data
|
|
31
|
+
* as JSON in the `text` content field — MCP-aware LLM clients can parse
|
|
32
|
+
* it; non-aware clients see human-readable JSON. The same payload is
|
|
33
|
+
* mirrored into `structuredContent` so tools declaring an `outputSchema`
|
|
34
|
+
* (#226) get SDK-validated structured output without per-tool plumbing.
|
|
35
|
+
*
|
|
36
|
+
* `structuredContent` is populated only when `payload` is an object —
|
|
37
|
+
* the MCP SDK's `structuredContent` slot expects an object shape, and
|
|
38
|
+
* array / primitive payloads stay in the `text` slot only.
|
|
39
|
+
*/
|
|
40
|
+
export declare function jsonSuccess(payload: unknown): ToolSuccessResponse;
|
|
41
|
+
/**
|
|
42
|
+
* Render a plain-text success response (useful for verbs like `remove` /
|
|
43
|
+
* `highlight` whose output is a confirmation, not structured data). Use
|
|
44
|
+
* {@link textWithStructuredSuccess} when the tool also declares an
|
|
45
|
+
* `outputSchema` requiring a typed acknowledgment.
|
|
46
|
+
*/
|
|
47
|
+
export declare function textSuccess(text: string): ToolSuccessResponse;
|
|
48
|
+
/**
|
|
49
|
+
* Render a confirmation line as the `text` content slot while also
|
|
50
|
+
* publishing a typed acknowledgment via `structuredContent`. Used by
|
|
51
|
+
* `*_remove` tools (#226) where the human-readable text stays for
|
|
52
|
+
* compatibility and the structured payload matches the tool's declared
|
|
53
|
+
* `outputSchema`.
|
|
54
|
+
*/
|
|
55
|
+
export declare function textWithStructuredSuccess(text: string, structuredContent: Record<string, unknown>): ToolSuccessResponse;
|
|
56
|
+
/**
|
|
57
|
+
* Map a domain error from any sub-domain into an MCP tool-error response.
|
|
58
|
+
*
|
|
59
|
+
* Routes through three branches:
|
|
60
|
+
* - `TtctlError` subclasses → uniform Error/Recovery/Code blocks
|
|
61
|
+
* - `profile.basic.ProfileError` → `(<CODE>): <message>` line
|
|
62
|
+
* - anything else → generic `text: <message>`
|
|
63
|
+
*
|
|
64
|
+
* `commandLabel` (e.g. `"profile.education.add"`) prefixes the error
|
|
65
|
+
* line for sub-domain disambiguation.
|
|
66
|
+
*/
|
|
67
|
+
export declare function presentToolError(commandLabel: string, err: unknown): ToolErrorResponse;
|
|
68
|
+
/**
|
|
69
|
+
* Resolve the auth-token path from `.ttctl.yaml` for an MCP tool. On
|
|
70
|
+
* `ConfigError`, returns the rendered tool-error response; on success,
|
|
71
|
+
* returns `{ token }`. The two-shape return lets the caller branch with
|
|
72
|
+
* `if ("error" in r) return r.error` instead of carrying try/catch.
|
|
73
|
+
*
|
|
74
|
+
* Post-#113: the resolver is a factory closure over the config path
|
|
75
|
+
* captured at MCP server startup. Per-call reads always target that path;
|
|
76
|
+
* env-var shifts during the session do NOT retarget the read.
|
|
77
|
+
*/
|
|
78
|
+
export type AuthResolution = {
|
|
79
|
+
token: string;
|
|
80
|
+
} | {
|
|
81
|
+
error: ToolErrorResponse;
|
|
82
|
+
};
|
|
83
|
+
export type CommandLabelTokenResolver = (commandLabel: string) => Promise<AuthResolution>;
|
|
84
|
+
export declare function createTokenResolver(configPath: string): CommandLabelTokenResolver;
|
|
85
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/tools/profile/shared.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD;;;;;;GAMG;AACH,eAAO,MAAM,SAAS,aAEuE,CAAC;AAE9F;;;;;;;;;GASG;AACH,MAAM,WAAW,mBAAmB;IAClC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACrB,OAAO,EAAE,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1C,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC7C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,mBAAmB,CAQjE;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,CAE7D;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACzC,mBAAmB,CAKrB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,iBAAiB,CAmBtF;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,cAAc,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,iBAAiB,CAAA;CAAE,CAAC;AAE9E,MAAM,MAAM,yBAAyB,GAAG,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;AAE1F,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,yBAAyB,CAmCjF"}
|