user-majico-mcp 0.7.5

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 (66) hide show
  1. package/README.md +144 -0
  2. package/dist/agent-bootstrap.d.ts +8 -0
  3. package/dist/agent-bootstrap.js +21 -0
  4. package/dist/auth-prompt.d.ts +13 -0
  5. package/dist/auth-prompt.js +15 -0
  6. package/dist/client-disconnect.d.ts +4 -0
  7. package/dist/client-disconnect.js +17 -0
  8. package/dist/credentials.d.ts +40 -0
  9. package/dist/credentials.js +60 -0
  10. package/dist/http-handler.d.ts +6 -0
  11. package/dist/http-handler.js +28 -0
  12. package/dist/index.d.ts +12 -0
  13. package/dist/index.js +22 -0
  14. package/dist/present-interactive.d.ts +92 -0
  15. package/dist/present-interactive.js +479 -0
  16. package/dist/present-types.d.ts +17 -0
  17. package/dist/present-types.js +1 -0
  18. package/dist/project-relevance.d.ts +27 -0
  19. package/dist/project-relevance.js +95 -0
  20. package/dist/project-selection-hints.d.ts +16 -0
  21. package/dist/project-selection-hints.js +32 -0
  22. package/dist/project-selection.d.ts +25 -0
  23. package/dist/project-selection.js +42 -0
  24. package/dist/recommended-external-skills.d.ts +39 -0
  25. package/dist/recommended-external-skills.js +319 -0
  26. package/dist/sdk-surface.d.ts +10 -0
  27. package/dist/sdk-surface.js +24 -0
  28. package/dist/server-branding.d.ts +17 -0
  29. package/dist/server-branding.js +40 -0
  30. package/dist/server.d.ts +3 -0
  31. package/dist/server.js +24 -0
  32. package/dist/svg-preview-block.d.ts +14 -0
  33. package/dist/svg-preview-block.js +82 -0
  34. package/dist/tools/constants.d.ts +47 -0
  35. package/dist/tools/constants.js +95 -0
  36. package/dist/tools/dispatch-branding-studio.d.ts +5 -0
  37. package/dist/tools/dispatch-branding-studio.js +197 -0
  38. package/dist/tools/dispatch-pulse-blog.d.ts +3 -0
  39. package/dist/tools/dispatch-pulse-blog.js +158 -0
  40. package/dist/tools/dispatch-research-assets.d.ts +3 -0
  41. package/dist/tools/dispatch-research-assets.js +132 -0
  42. package/dist/tools/handle-tool-call-pre.d.ts +4 -0
  43. package/dist/tools/handle-tool-call-pre.js +47 -0
  44. package/dist/tools/handle-tool-call.d.ts +3 -0
  45. package/dist/tools/handle-tool-call.js +56 -0
  46. package/dist/tools/tool-call-helpers.d.ts +22 -0
  47. package/dist/tools/tool-call-helpers.js +104 -0
  48. package/dist/tools/tool-catalog.d.ts +14 -0
  49. package/dist/tools/tool-catalog.js +54 -0
  50. package/dist/tools/tool-definitions-blog-git.d.ts +2 -0
  51. package/dist/tools/tool-definitions-blog-git.js +207 -0
  52. package/dist/tools/tool-definitions-branding.d.ts +2 -0
  53. package/dist/tools/tool-definitions-branding.js +197 -0
  54. package/dist/tools/tool-definitions-research-aliases.d.ts +2 -0
  55. package/dist/tools/tool-definitions-research-aliases.js +340 -0
  56. package/dist/tools/tool-definitions-studio-pulse.d.ts +2 -0
  57. package/dist/tools/tool-definitions-studio-pulse.js +235 -0
  58. package/dist/tools/tool-matrix.d.ts +12 -0
  59. package/dist/tools/tool-matrix.js +36 -0
  60. package/dist/tools.d.ts +5 -0
  61. package/dist/tools.js +3 -0
  62. package/dist/ui-ux-skills.d.ts +33 -0
  63. package/dist/ui-ux-skills.js +157 -0
  64. package/dist/user-pick-policy.d.ts +18 -0
  65. package/dist/user-pick-policy.js +21 -0
  66. package/package.json +71 -0
@@ -0,0 +1,47 @@
1
+ import type { Tool } from "@modelcontextprotocol/sdk/types.js";
2
+ export declare const MCP_SERVER_VERSION = "0.9.0";
3
+ export declare const ASK_USER_PROJECT_SCOPE = " Before other tools: call ping, then ask the user whether to use an existing Majico project (list_projects) or create_project for this request; pass projectId on tool calls once confirmed.";
4
+ export declare const MCP_AUTH_TOOL_DESCRIPTION = "Authenticate the Majico MCP server with OAuth in Cursor. If ping fails or any tool returns authRequired: true, stop and ask the user to Connect before other tools. Call this tool to get the exact user-facing prompt to display verbatim.";
5
+ export declare function withBrandingAuthStep(tool: Tool): Tool;
6
+ export declare const optionalCredentialProps: {
7
+ readonly projectId: {
8
+ readonly type: "string";
9
+ readonly description: "Majico project UUID (optional when connected via Cursor OAuth or env defaults)";
10
+ };
11
+ readonly apiKey: {
12
+ readonly type: "string";
13
+ readonly description: "Project API key (optional when connected via Cursor OAuth or env defaults)";
14
+ };
15
+ };
16
+ export declare const projectContextProps: {
17
+ readonly consumerRepo: {
18
+ readonly type: "string";
19
+ readonly description: "Consumer repo path or folder name (e.g. reeldemo-ableton) for relevance ranking. Defaults to MAJICO_CONSUMER_REPO or process.cwd().";
20
+ };
21
+ readonly requestContext: {
22
+ readonly type: "string";
23
+ readonly description: "Short summary of the user's request (product, task, audience) to rank the 3–5 most relevant projects by name and description.";
24
+ };
25
+ };
26
+ export declare function resolveProjectRelevanceContext(args?: Record<string, unknown>): {
27
+ consumerRepoPath: string;
28
+ requestContext: string | undefined;
29
+ };
30
+ export declare const stableBrandMarkdownProps: {
31
+ readonly productName: {
32
+ readonly type: "string";
33
+ readonly description: "Product or brand name";
34
+ };
35
+ readonly positioningConcept: {
36
+ readonly type: "string";
37
+ readonly description: "One-line positioning or concept statement";
38
+ };
39
+ readonly audience: {
40
+ readonly type: "string";
41
+ readonly description: "Primary audience or customer segment";
42
+ };
43
+ readonly tone: {
44
+ readonly type: "string";
45
+ readonly description: "Brand tone or voice guidelines";
46
+ };
47
+ };
@@ -0,0 +1,95 @@
1
+ import { AUTH_FIRST_STEP } from "../auth-prompt.js";
2
+ export const MCP_SERVER_VERSION = "0.9.0";
3
+ export const ASK_USER_PROJECT_SCOPE = " Before other tools: call ping, then ask the user whether to use an existing Majico project (list_projects) or create_project for this request; pass projectId on tool calls once confirmed.";
4
+ export const MCP_AUTH_TOOL_DESCRIPTION = "Authenticate the Majico MCP server with OAuth in Cursor. If ping fails or any tool returns authRequired: true, stop and ask the user to Connect before other tools. Call this tool to get the exact user-facing prompt to display verbatim.";
5
+ const BRANDING_TOOL_NAMES = new Set([
6
+ "get_brand_profile",
7
+ "get_design_tokens",
8
+ "get_logo_svg",
9
+ "list_logo_candidates",
10
+ "select_logo",
11
+ "get_cursor_handoff",
12
+ "ack_cursor_handoff",
13
+ "get_guidelines",
14
+ "get_design_md",
15
+ "get_brand_md",
16
+ "get_ui_ux_skills",
17
+ "sync_cursor_skills",
18
+ "update_cursor_skill",
19
+ "get_studio_canvas",
20
+ "get_export_manifest",
21
+ "download_export_zip",
22
+ "submit_brief",
23
+ "list_palette_options",
24
+ "select_palette",
25
+ "update_studio_html_frame",
26
+ "generate_creative",
27
+ "refine_creative",
28
+ "push_design_tokens_to_figma",
29
+ "sync_project_assets_to_figma",
30
+ "import_repo",
31
+ "publish_landing_page",
32
+ "brand",
33
+ "tokens",
34
+ "logos",
35
+ "guidelines",
36
+ "design_md",
37
+ "studio",
38
+ "export_manifest",
39
+ "submit_brief",
40
+ "cursor_handoff",
41
+ ]);
42
+ export function withBrandingAuthStep(tool) {
43
+ if (!BRANDING_TOOL_NAMES.has(tool.name))
44
+ return tool;
45
+ return {
46
+ ...tool,
47
+ description: AUTH_FIRST_STEP + tool.description,
48
+ };
49
+ }
50
+ export const optionalCredentialProps = {
51
+ projectId: {
52
+ type: "string",
53
+ description: "Majico project UUID (optional when connected via Cursor OAuth or env defaults)",
54
+ },
55
+ apiKey: {
56
+ type: "string",
57
+ description: "Project API key (optional when connected via Cursor OAuth or env defaults)",
58
+ },
59
+ };
60
+ export const projectContextProps = {
61
+ consumerRepo: {
62
+ type: "string",
63
+ description: "Consumer repo path or folder name (e.g. reeldemo-ableton) for relevance ranking. Defaults to MAJICO_CONSUMER_REPO or process.cwd().",
64
+ },
65
+ requestContext: {
66
+ type: "string",
67
+ description: "Short summary of the user's request (product, task, audience) to rank the 3–5 most relevant projects by name and description.",
68
+ },
69
+ };
70
+ export function resolveProjectRelevanceContext(args) {
71
+ return {
72
+ consumerRepoPath: args?.consumerRepo?.trim() ||
73
+ process.env.MAJICO_CONSUMER_REPO?.trim() ||
74
+ process.cwd(),
75
+ requestContext: args?.requestContext?.trim(),
76
+ };
77
+ }
78
+ export const stableBrandMarkdownProps = {
79
+ productName: {
80
+ type: "string",
81
+ description: "Product or brand name",
82
+ },
83
+ positioningConcept: {
84
+ type: "string",
85
+ description: "One-line positioning or concept statement",
86
+ },
87
+ audience: {
88
+ type: "string",
89
+ description: "Primary audience or customer segment",
90
+ },
91
+ tone: {
92
+ type: "string",
93
+ description: "Brand tone or voice guidelines",
94
+ },
95
+ };
@@ -0,0 +1,5 @@
1
+ import type { MajicoClient } from "@majico/sdk";
2
+ import type { CredentialSource, ResolvedCredentials } from "../credentials.js";
3
+ import type { PresentContext } from "../present-interactive.js";
4
+ import { type ToolCallResult } from "./tool-call-helpers.js";
5
+ export declare function dispatchBrandingStudioTool(name: string, args: Record<string, unknown> | undefined, client: MajicoClient, creds: ResolvedCredentials, ctx: PresentContext, defaultCredentials?: CredentialSource): Promise<ToolCallResult | null>;
@@ -0,0 +1,197 @@
1
+ import { presentCursorHandoff, presentLogoCandidates, presentPaletteOptions, } from "../present-interactive.js";
2
+ import { buildProjectSelectionFields, PROJECT_SELECTION_HINT, } from "../project-selection.js";
3
+ import { pickRelevantProjects } from "../project-relevance.js";
4
+ import { inferRepoNameHints } from "../project-selection-hints.js";
5
+ import { validateUserPickGate } from "../user-pick-policy.js";
6
+ import { MCP_SERVER_VERSION, resolveProjectRelevanceContext, } from "./constants.js";
7
+ import { toolError, toolJson, toolPresent, requireStringArg, } from "./tool-call-helpers.js";
8
+ export async function dispatchBrandingStudioTool(name, args, client, creds, ctx, defaultCredentials) {
9
+ switch (name) {
10
+ case "ping":
11
+ case "health": {
12
+ const ping = await client.projects.ping();
13
+ const list = await client.projects.list();
14
+ const explicitProjectId = args?.projectId;
15
+ const relevanceContext = resolveProjectRelevanceContext(args);
16
+ const selection = buildProjectSelectionFields({
17
+ projects: list.projects,
18
+ activeProjectId: creds.projectId,
19
+ activeProjectName: ping.projectName,
20
+ explicitProjectId,
21
+ consumerRepoPath: relevanceContext.consumerRepoPath,
22
+ requestContext: relevanceContext.requestContext,
23
+ });
24
+ return toolJson({
25
+ ok: true,
26
+ auth: defaultCredentials?.auth ?? "api_key",
27
+ userId: defaultCredentials?.userId ?? ping.userId,
28
+ projectId: creds.projectId,
29
+ projectName: ping.projectName,
30
+ hasBrandData: ping.hasBrandData,
31
+ hasCanvasData: ping.hasCanvasData,
32
+ previewToken: ping.previewToken ?? null,
33
+ previewPickerUrl: ping.previewPickerUrl ?? null,
34
+ baseUrl: creds.baseUrl,
35
+ serverVersion: MCP_SERVER_VERSION,
36
+ ...(selection ?? {}),
37
+ });
38
+ }
39
+ case "list_projects": {
40
+ const list = await client.projects.list();
41
+ const relevantProjects = pickRelevantProjects(list.projects, resolveProjectRelevanceContext(args));
42
+ return toolJson({
43
+ ...list,
44
+ relevantProjects,
45
+ totalProjectCount: list.projects.length,
46
+ hint: PROJECT_SELECTION_HINT,
47
+ });
48
+ }
49
+ case "create_project": {
50
+ const projectName = requireStringArg(args, "name");
51
+ if (!projectName)
52
+ return toolError("name is required.");
53
+ return toolJson(await client.projects.create(projectName));
54
+ }
55
+ case "brand":
56
+ case "get_brand_profile":
57
+ return toolJson(await client.brand.get());
58
+ case "tokens":
59
+ case "get_design_tokens":
60
+ return toolJson(await client.tokens.get());
61
+ case "get_logo_svg":
62
+ return toolJson(await client.logo.get());
63
+ case "logos":
64
+ case "list_logo_candidates":
65
+ return toolPresent(await presentLogoCandidates(await client.logo.listCandidates(args?.flowId), ctx));
66
+ case "select_logo": {
67
+ const pickError = validateUserPickGate({
68
+ userConfirmed: args?.userConfirmed === true,
69
+ userDelegatedPick: args?.userDelegatedPick === true,
70
+ }, "select_logo");
71
+ if (pickError)
72
+ return toolError(pickError);
73
+ return toolJson(await client.logo.select({
74
+ candidateId: args?.candidateId,
75
+ templateId: args?.templateId,
76
+ svg: args?.svg,
77
+ flowId: args?.flowId,
78
+ }));
79
+ }
80
+ case "cursor_handoff":
81
+ case "get_cursor_handoff":
82
+ return toolPresent(presentCursorHandoff(await client.cursorHandoff.get()));
83
+ case "ack_cursor_handoff": {
84
+ const handoffId = args?.handoffId;
85
+ if (!handoffId?.trim())
86
+ return toolError("handoffId is required.");
87
+ return toolJson(await client.cursorHandoff.ack(handoffId.trim()));
88
+ }
89
+ case "guidelines":
90
+ case "get_guidelines":
91
+ return toolJson(await client.guidelines.get());
92
+ case "design_md":
93
+ case "get_design_md":
94
+ return toolJson(await client.designMd.get());
95
+ case "get_brand_md":
96
+ return toolJson(await client.brandMd.get());
97
+ case "sync_cursor_skills":
98
+ return toolJson(await client.cursorSkills.syncInstallManifest());
99
+ case "update_cursor_skill": {
100
+ const skillSlug = requireStringArg(args, "skillSlug");
101
+ if (!skillSlug)
102
+ return toolError("skillSlug is required.");
103
+ return toolJson(await client.cursorSkills.update({
104
+ skillSlug,
105
+ name: args?.name,
106
+ description: args?.description,
107
+ bodyMd: args?.bodyMd,
108
+ phase: args?.phase,
109
+ priority: typeof args?.priority === "number" ? args.priority : undefined,
110
+ enabled: typeof args?.enabled === "boolean" ? args.enabled : undefined,
111
+ }));
112
+ }
113
+ case "studio":
114
+ case "get_studio_canvas":
115
+ return toolJson(await client.studio.get());
116
+ case "export_manifest":
117
+ case "get_export_manifest":
118
+ return toolJson(await client.export.getManifest());
119
+ case "download_export_zip": {
120
+ const buffer = await client.export.downloadZip();
121
+ const bytes = Buffer.from(buffer);
122
+ const manifest = await client.export.getManifest().catch(() => null);
123
+ const slug = manifest?.productName?.replace(/[^a-z0-9]+/gi, "-").toLowerCase() ||
124
+ "brand";
125
+ return toolJson({
126
+ filename: `${slug}-brand-export.zip`,
127
+ sizeBytes: bytes.length,
128
+ base64: bytes.toString("base64"),
129
+ manifest: manifest ?? undefined,
130
+ agentInstructions: "Decode base64 and write the ZIP to disk, or extract BRAND.md, DESIGN.md, and tokens/ into the consumer repo.",
131
+ });
132
+ }
133
+ case "submit_brief": {
134
+ const productName = args?.productName;
135
+ const oneLiner = args?.oneLiner;
136
+ if (!productName?.trim() || !oneLiner?.trim()) {
137
+ return toolError("productName and oneLiner are required.");
138
+ }
139
+ return toolJson(await client.brief.submit({
140
+ productName: productName.trim(),
141
+ oneLiner: oneLiner.trim(),
142
+ audience: args?.audience,
143
+ nicheKeywords: args?.nicheKeywords,
144
+ goals: args?.goals,
145
+ constraints: args?.constraints,
146
+ marketRealityScan: args?.marketRealityScan === true,
147
+ operatingMode: args?.operatingMode,
148
+ }));
149
+ }
150
+ case "update_studio_html_frame": {
151
+ const elementId = args?.elementId;
152
+ const html = args?.html;
153
+ if (!elementId?.trim() || typeof html !== "string") {
154
+ return toolError("elementId and html are required.");
155
+ }
156
+ return toolJson(await client.studio.patchHtmlFrame({
157
+ elementId: elementId.trim(),
158
+ html,
159
+ }));
160
+ }
161
+ case "generate_creative":
162
+ return toolJson(await client.creative.generate({
163
+ slotId: args?.slotId,
164
+ prompt: args?.prompt,
165
+ slots: args?.slots,
166
+ }));
167
+ case "refine_creative":
168
+ return toolJson(await client.creative.refine({
169
+ slotId: args?.slotId,
170
+ refinePrompt: args?.refinePrompt,
171
+ prompt: args?.prompt,
172
+ }));
173
+ case "list_palette_options": {
174
+ const consumerRepoPath = args?.consumerRepo?.trim() ||
175
+ process.env.MAJICO_CONSUMER_REPO?.trim() ||
176
+ process.cwd();
177
+ return toolPresent(await presentPaletteOptions(await client.palette.listCandidates(), {
178
+ ...ctx,
179
+ repoHints: inferRepoNameHints(consumerRepoPath),
180
+ }));
181
+ }
182
+ case "select_palette": {
183
+ const optionId = args?.optionId;
184
+ if (!optionId?.trim())
185
+ return toolError("optionId is required.");
186
+ const pickError = validateUserPickGate({
187
+ userConfirmed: args?.userConfirmed === true,
188
+ userDelegatedPick: args?.userDelegatedPick === true,
189
+ }, "select_palette");
190
+ if (pickError)
191
+ return toolError(pickError);
192
+ return toolJson(await client.palette.select({ optionId: optionId.trim() }));
193
+ }
194
+ default:
195
+ return null;
196
+ }
197
+ }
@@ -0,0 +1,3 @@
1
+ import type { MajicoClient } from "@majico/sdk";
2
+ import { type ToolCallResult } from "./tool-call-helpers.js";
3
+ export declare function dispatchPulseBlogTool(name: string, args: Record<string, unknown> | undefined, client: MajicoClient): Promise<ToolCallResult | null>;
@@ -0,0 +1,158 @@
1
+ import { presentTweetDrafts, } from "../present-interactive.js";
2
+ import { toolError, toolJson, toolPresent, } from "./tool-call-helpers.js";
3
+ export async function dispatchPulseBlogTool(name, args, client) {
4
+ switch (name) {
5
+ case "get_pulse_status":
6
+ return toolJson(await client.pulse.getStatus());
7
+ case "generate_tweet_drafts":
8
+ return toolPresent(presentTweetDrafts(await client.pulse.generateTweetDrafts({
9
+ prompt: args?.prompt,
10
+ })));
11
+ case "select_tweet_draft": {
12
+ const draftId = args?.draftId;
13
+ const text = args?.text;
14
+ if (!draftId?.trim() || !text?.trim()) {
15
+ return toolError("draftId and text are required.");
16
+ }
17
+ return toolJson(await client.pulse.selectTweetDraft({
18
+ draftId: draftId.trim(),
19
+ text: text.trim(),
20
+ }));
21
+ }
22
+ case "list_pulse_posts":
23
+ return toolJson(await client.pulse.listPosts({
24
+ sort: args?.sort,
25
+ limit: typeof args?.limit === "number" ? args.limit : undefined,
26
+ }));
27
+ case "list_calendar_slots":
28
+ return toolJson(await client.pulse.listCalendarSlots({
29
+ limit: typeof args?.limit === "number" ? args.limit : undefined,
30
+ platform: args?.platform,
31
+ }));
32
+ case "generate_post_variants": {
33
+ const slotId = args?.slotId;
34
+ if (!slotId?.trim())
35
+ return toolError("slotId is required.");
36
+ return toolJson(await client.pulse.generatePostVariants({
37
+ slotId: slotId.trim(),
38
+ prompt: args?.prompt,
39
+ }));
40
+ }
41
+ case "select_post_variant": {
42
+ const slotId = args?.slotId;
43
+ const variantId = args?.variantId;
44
+ if (!slotId?.trim() || !variantId?.trim()) {
45
+ return toolError("slotId and variantId are required.");
46
+ }
47
+ return toolJson(await client.pulse.selectPostVariant({
48
+ slotId: slotId.trim(),
49
+ variantId: variantId.trim(),
50
+ }));
51
+ }
52
+ case "approve_publish_slot": {
53
+ const slotId = args?.slotId;
54
+ if (!slotId?.trim())
55
+ return toolError("slotId is required.");
56
+ return toolJson(await client.pulse.approvePublishSlot({ slotId: slotId.trim() }));
57
+ }
58
+ case "schedule_publish_slot": {
59
+ const slotId = args?.slotId;
60
+ const scheduledAt = args?.scheduledAt;
61
+ if (!slotId?.trim() || !scheduledAt?.trim()) {
62
+ return toolError("slotId and scheduledAt are required.");
63
+ }
64
+ return toolJson(await client.pulse.schedulePublishSlot({
65
+ slotId: slotId.trim(),
66
+ scheduledAt: scheduledAt.trim(),
67
+ }));
68
+ }
69
+ case "get_performance_insights":
70
+ return toolJson(await client.pulse.getPerformanceInsights());
71
+ case "get_product_ops_view":
72
+ return toolJson(await client.pulse.getProductOpsView());
73
+ case "list_blog_posts":
74
+ return toolJson(await client.blog.listPosts({
75
+ limit: typeof args?.limit === "number" ? args.limit : undefined,
76
+ }));
77
+ case "get_blog_post": {
78
+ const postId = args?.postId;
79
+ if (!postId?.trim())
80
+ return toolError("postId is required.");
81
+ return toolJson(await client.blog.getPost(postId.trim()));
82
+ }
83
+ case "get_blog_seo_handoff": {
84
+ return toolJson(await client.blog.seoHandoff({
85
+ postId: args?.postId?.trim() || undefined,
86
+ }));
87
+ }
88
+ case "suggest_blog_opportunities":
89
+ return toolJson(await client.blog.suggestOpportunities());
90
+ case "run_blog_research": {
91
+ const concept = args?.concept;
92
+ if (!concept || typeof concept !== "object") {
93
+ return toolError("concept object is required.");
94
+ }
95
+ return toolJson(await client.blog.runResearch({
96
+ concept: concept,
97
+ articleType: args?.articleType,
98
+ postId: args?.postId,
99
+ }));
100
+ }
101
+ case "generate_blog_outline": {
102
+ const concept = args?.concept;
103
+ const dossier = args?.dossier;
104
+ if (!concept || typeof concept !== "object") {
105
+ return toolError("concept object is required.");
106
+ }
107
+ if (!dossier || typeof dossier !== "object") {
108
+ return toolError("dossier object is required.");
109
+ }
110
+ return toolJson(await client.blog.generateOutline({
111
+ concept: concept,
112
+ dossier: dossier,
113
+ articleType: args?.articleType,
114
+ postId: args?.postId,
115
+ }));
116
+ }
117
+ case "approve_blog_outline": {
118
+ const postId = args?.postId;
119
+ if (!postId?.trim())
120
+ return toolError("postId is required.");
121
+ return toolJson(await client.blog.approveOutline({ postId: postId.trim() }));
122
+ }
123
+ case "generate_blog_section": {
124
+ const postId = args?.postId;
125
+ const sectionId = args?.sectionId;
126
+ if (!postId?.trim() || !sectionId?.trim()) {
127
+ return toolError("postId and sectionId are required.");
128
+ }
129
+ return toolJson(await client.blog.generateSection({
130
+ postId: postId.trim(),
131
+ sectionId: sectionId.trim(),
132
+ approve: args?.approve === true,
133
+ }));
134
+ }
135
+ case "assemble_blog_post": {
136
+ const postId = args?.postId;
137
+ if (!postId?.trim())
138
+ return toolError("postId is required.");
139
+ return toolJson(await client.blog.assemble({
140
+ postId: postId.trim(),
141
+ skipSeoGate: args?.skipSeoGate === true,
142
+ }));
143
+ }
144
+ case "publish_blog_post": {
145
+ const postId = args?.postId;
146
+ if (!postId?.trim())
147
+ return toolError("postId is required.");
148
+ const scope = args?.scope;
149
+ return toolJson(await client.blog.publish({
150
+ postId: postId.trim(),
151
+ scope: scope === "platform" || scope === "project" ? scope : undefined,
152
+ force: args?.force === true,
153
+ }));
154
+ }
155
+ default:
156
+ return null;
157
+ }
158
+ }
@@ -0,0 +1,3 @@
1
+ import type { MajicoClient } from "@majico/sdk";
2
+ import { type ToolCallResult } from "./tool-call-helpers.js";
3
+ export declare function dispatchResearchAssetsTool(name: string, args: Record<string, unknown> | undefined, client: MajicoClient): Promise<ToolCallResult | null>;
@@ -0,0 +1,132 @@
1
+ import { toolError, toolJson, } from "./tool-call-helpers.js";
2
+ export async function dispatchResearchAssetsTool(name, args, client) {
3
+ switch (name) {
4
+ case "push_design_tokens_to_figma":
5
+ return toolJson(await client.figma.pushDesignTokens({
6
+ fileKey: args?.fileKey,
7
+ }));
8
+ case "sync_project_assets_to_figma":
9
+ return toolJson(await client.figma.syncProjectAssets({
10
+ fileKey: args?.fileKey,
11
+ }));
12
+ case "import_repo": {
13
+ const owner = args?.owner;
14
+ const repo = args?.repo;
15
+ if (!owner?.trim() || !repo?.trim()) {
16
+ return toolError("owner and repo are required.");
17
+ }
18
+ return toolJson(await client.git.importRepo({
19
+ owner: owner.trim(),
20
+ repo: repo.trim(),
21
+ ref: args?.ref,
22
+ provider: args?.provider,
23
+ }));
24
+ }
25
+ case "publish_landing_page":
26
+ return toolJson(await client.git.publishLandingPage({
27
+ target: args?.target,
28
+ provider: args?.provider,
29
+ elementId: args?.elementId,
30
+ html: args?.html,
31
+ owner: args?.owner,
32
+ repo: args?.repo,
33
+ branch: args?.branch,
34
+ orgLandingPath: args?.orgLandingPath,
35
+ }));
36
+ case "run_niche_research":
37
+ return toolJson(await client.research.runNicheResearch({
38
+ brief: args?.brief,
39
+ marketScan: typeof args?.marketScan === "boolean" ? args.marketScan : undefined,
40
+ sourceFlowId: args?.sourceFlowId,
41
+ }));
42
+ case "run_market_scan":
43
+ return toolJson(await client.research.runMarketScan({
44
+ keywords: args?.keywords,
45
+ productName: args?.productName,
46
+ oneLiner: args?.oneLiner,
47
+ audience: args?.audience,
48
+ }));
49
+ case "web_search": {
50
+ const query = args?.query;
51
+ if (!query?.trim())
52
+ return toolError("query is required.");
53
+ return toolJson(await client.research.webSearch({
54
+ query: query.trim(),
55
+ limit: typeof args?.limit === "number" ? args.limit : undefined,
56
+ }));
57
+ }
58
+ case "run_asset_research": {
59
+ const skillId = args?.skillId;
60
+ if (!skillId?.trim())
61
+ return toolError("skillId is required.");
62
+ return toolJson(await client.research.runAssetResearch({
63
+ skillId: skillId.trim(),
64
+ context: args?.context,
65
+ refresh: args?.refresh,
66
+ }));
67
+ }
68
+ case "generate_asset": {
69
+ const skillId = args?.skillId;
70
+ if (!skillId?.trim())
71
+ return toolError("skillId is required.");
72
+ return toolJson(await client.assets.generate({
73
+ skillId: skillId.trim(),
74
+ elementId: args?.elementId,
75
+ flowGroupId: args?.flowGroupId,
76
+ params: args?.params,
77
+ context: args?.context,
78
+ forceResearchRefresh: args?.forceResearchRefresh === true,
79
+ }));
80
+ }
81
+ case "patch_investor_ask_slide": {
82
+ const raiseAmount = args?.raiseAmount;
83
+ const useOfFunds = args?.useOfFunds;
84
+ if (!raiseAmount?.trim())
85
+ return toolError("raiseAmount is required.");
86
+ if (!Array.isArray(useOfFunds) || useOfFunds.length === 0) {
87
+ return toolError("useOfFunds is required.");
88
+ }
89
+ return toolJson(await client.assets.patchInvestorAskSlide({
90
+ raiseAmount: raiseAmount.trim(),
91
+ useOfFunds,
92
+ deckElementId: args?.deckElementId,
93
+ headline: args?.headline,
94
+ }));
95
+ }
96
+ case "get_asset_status": {
97
+ const jobId = args?.jobId;
98
+ if (!jobId?.trim())
99
+ return toolError("jobId is required.");
100
+ return toolJson(await client.assets.getStatus({ jobId: jobId.trim() }));
101
+ }
102
+ case "list_project_assets":
103
+ return toolJson(await client.assets.list({
104
+ skillId: args?.skillId,
105
+ limit: typeof args?.limit === "number" ? args.limit : undefined,
106
+ }));
107
+ case "quiver_generate_svg": {
108
+ const prompt = args?.prompt;
109
+ if (!prompt?.trim())
110
+ return toolError("prompt is required.");
111
+ return toolJson(await client.quiver.generateSvg({
112
+ prompt: prompt.trim(),
113
+ model: args?.model,
114
+ n: typeof args?.n === "number" ? args.n : undefined,
115
+ instructions: args?.instructions,
116
+ }));
117
+ }
118
+ case "quiver_vectorize_svg": {
119
+ const imageBase64 = args?.imageBase64;
120
+ if (!imageBase64?.trim())
121
+ return toolError("imageBase64 is required.");
122
+ return toolJson(await client.quiver.vectorizeSvg({
123
+ imageBase64: imageBase64.trim(),
124
+ model: args?.model,
125
+ autoCrop: args?.autoCrop === true,
126
+ targetSize: typeof args?.targetSize === "number" ? args.targetSize : undefined,
127
+ }));
128
+ }
129
+ default:
130
+ return null;
131
+ }
132
+ }
@@ -0,0 +1,4 @@
1
+ import type { CredentialSource } from "../credentials.js";
2
+ import { type ToolCallResult } from "./tool-call-helpers.js";
3
+ /** Pre-client tools and plan gate checks. */
4
+ export declare function handlePreClientToolCall(name: string, args: Record<string, unknown> | undefined, defaultCredentials?: CredentialSource): Promise<ToolCallResult | null>;