posterly-mcp-server 0.44.0 → 0.45.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/README.md +310 -111
- package/dist/index.js +190 -894
- package/dist/lib/alias-transport.d.ts +84 -0
- package/dist/lib/alias-transport.js +193 -0
- package/dist/lib/api-client.d.ts +18 -0
- package/dist/lib/api-client.js +55 -0
- package/dist/lib/preview-token-core.d.ts +62 -0
- package/dist/lib/preview-token-core.js +131 -0
- package/dist/lib/preview-token.d.ts +23 -0
- package/dist/lib/preview-token.js +44 -0
- package/dist/lib/tool-registry.d.ts +246 -0
- package/dist/lib/tool-registry.js +394 -0
- package/dist/lib/tool-runtime.d.ts +68 -0
- package/dist/lib/tool-runtime.js +85 -0
- package/dist/lib/version.d.ts +1 -1
- package/dist/lib/version.js +1 -1
- package/dist/tools/audit-google-business-profile.js +1 -1
- package/dist/tools/connect-account.d.ts +4 -4
- package/dist/tools/connect-account.js +2 -2
- package/dist/tools/create-connect-session.d.ts +2 -2
- package/dist/tools/create-connect-session.js +2 -2
- package/dist/tools/create-post.d.ts +6 -6
- package/dist/tools/create-post.js +3 -3
- package/dist/tools/create-posts-batch.d.ts +4 -4
- package/dist/tools/create-webhook.d.ts +2 -2
- package/dist/tools/delete-post.d.ts +34 -10
- package/dist/tools/delete-post.js +52 -16
- package/dist/tools/generate-captions.d.ts +2 -2
- package/dist/tools/generate-image.d.ts +4 -4
- package/dist/tools/generate-image.js +2 -2
- package/dist/tools/generate-video.d.ts +6 -6
- package/dist/tools/generate-video.js +1 -1
- package/dist/tools/get-agent-signup-info.js +2 -2
- package/dist/tools/get-post.d.ts +16 -1
- package/dist/tools/get-post.js +35 -19
- package/dist/tools/list-accounts.d.ts +49 -3
- package/dist/tools/list-accounts.js +148 -33
- package/dist/tools/list-analytics.d.ts +111 -0
- package/dist/tools/list-analytics.js +393 -0
- package/dist/tools/list-brands.d.ts +38 -3
- package/dist/tools/list-brands.js +138 -20
- package/dist/tools/list-comments.d.ts +29 -9
- package/dist/tools/list-comments.js +75 -34
- package/dist/tools/list-conversations.d.ts +32 -9
- package/dist/tools/list-conversations.js +63 -27
- package/dist/tools/list-google-business-media.js +1 -1
- package/dist/tools/list-google-business-reviews.d.ts +32 -9
- package/dist/tools/list-google-business-reviews.js +77 -52
- package/dist/tools/list-jobs.d.ts +60 -0
- package/dist/tools/list-jobs.js +81 -0
- package/dist/tools/list-platforms.d.ts +62 -3
- package/dist/tools/list-platforms.js +118 -9
- package/dist/tools/list-posts.d.ts +2 -2
- package/dist/tools/manage-comment.d.ts +102 -0
- package/dist/tools/manage-comment.js +125 -0
- package/dist/tools/manage-conversation.d.ts +79 -0
- package/dist/tools/manage-conversation.js +75 -0
- package/dist/tools/manage-google-business-media.d.ts +103 -0
- package/dist/tools/manage-google-business-media.js +126 -0
- package/dist/tools/manage-google-business-review.d.ts +146 -0
- package/dist/tools/manage-google-business-review.js +115 -0
- package/dist/tools/manage-oauth-client.d.ts +121 -0
- package/dist/tools/manage-oauth-client.js +94 -0
- package/dist/tools/manage-webhook.d.ts +99 -0
- package/dist/tools/manage-webhook.js +87 -0
- package/dist/tools/start-signup.d.ts +2 -2
- package/dist/tools/submit-agent-feedback.d.ts +4 -4
- package/dist/tools/trigger-platform-helper.d.ts +2 -2
- package/dist/tools/update-post.d.ts +62 -11
- package/dist/tools/update-post.js +79 -26
- package/dist/tools/upload-media.d.ts +32 -9
- package/dist/tools/upload-media.js +54 -18
- package/dist/tools/validate-post.d.ts +4 -4
- package/dist/tools/whoami.d.ts +15 -2
- package/dist/tools/whoami.js +221 -25
- package/package.json +5 -3
- package/scripts/test-alias-transport.mjs +368 -0
- package/scripts/test-client-header-sanitization.mjs +78 -0
- package/scripts/test-tool-annotations.mjs +38 -17
- package/server.json +9 -2
- package/src/index.ts +227 -1443
- package/src/lib/alias-transport.ts +233 -0
- package/src/lib/api-client.ts +65 -0
- package/src/lib/preview-token-core.ts +157 -0
- package/src/lib/preview-token.ts +54 -0
- package/src/lib/tool-registry.ts +538 -0
- package/src/lib/tool-runtime.ts +117 -0
- package/src/lib/version.ts +1 -1
- package/src/tools/audit-google-business-profile.ts +1 -1
- package/src/tools/connect-account.ts +2 -2
- package/src/tools/create-connect-session.ts +2 -2
- package/src/tools/create-post.ts +3 -3
- package/src/tools/delete-post.ts +60 -19
- package/src/tools/generate-image.ts +2 -2
- package/src/tools/generate-video.ts +1 -1
- package/src/tools/get-agent-signup-info.ts +2 -2
- package/src/tools/get-post.ts +35 -21
- package/src/tools/list-accounts.ts +187 -39
- package/src/tools/list-analytics.ts +444 -0
- package/src/tools/list-brands.ts +162 -26
- package/src/tools/list-comments.ts +86 -43
- package/src/tools/list-conversations.ts +81 -39
- package/src/tools/list-google-business-media.ts +1 -1
- package/src/tools/list-google-business-reviews.ts +93 -64
- package/src/tools/list-jobs.ts +91 -0
- package/src/tools/list-platforms.ts +135 -11
- package/src/tools/manage-comment.ts +142 -0
- package/src/tools/manage-conversation.ts +89 -0
- package/src/tools/manage-google-business-media.ts +147 -0
- package/src/tools/manage-google-business-review.ts +139 -0
- package/src/tools/manage-oauth-client.ts +116 -0
- package/src/tools/manage-webhook.ts +103 -0
- package/src/tools/update-post.ts +106 -39
- package/src/tools/upload-media.ts +76 -28
- package/src/tools/whoami.ts +253 -30
- package/tool-annotations.json +76 -149
- package/tool-registry.json +2085 -0
- package/src/tools/add-google-business-media.ts +0 -50
- package/src/tools/create-oauth-client.ts +0 -36
- package/src/tools/delete-comment.ts +0 -29
- package/src/tools/delete-google-business-media.ts +0 -30
- package/src/tools/delete-google-business-review-reply.ts +0 -30
- package/src/tools/delete-oauth-client.ts +0 -23
- package/src/tools/delete-post-group.ts +0 -17
- package/src/tools/delete-webhook.ts +0 -17
- package/src/tools/get-account-analytics.ts +0 -171
- package/src/tools/get-brand-profile.ts +0 -86
- package/src/tools/get-brand.ts +0 -34
- package/src/tools/get-comment.ts +0 -47
- package/src/tools/get-connect-link.ts +0 -61
- package/src/tools/get-connect-session.ts +0 -63
- package/src/tools/get-conversation.ts +0 -44
- package/src/tools/get-google-business-review-link.ts +0 -30
- package/src/tools/get-image-job.ts +0 -36
- package/src/tools/get-learned-voice.ts +0 -31
- package/src/tools/get-mcp-status.ts +0 -212
- package/src/tools/get-performance-profile.ts +0 -47
- package/src/tools/get-platform-schema.ts +0 -56
- package/src/tools/get-post-analytics.ts +0 -243
- package/src/tools/get-post-insights.ts +0 -60
- package/src/tools/get-post-missing.ts +0 -16
- package/src/tools/get-video-job.ts +0 -36
- package/src/tools/list-brand-accounts.ts +0 -36
- package/src/tools/reply-google-business-review.ts +0 -32
- package/src/tools/reply-to-comment.ts +0 -30
- package/src/tools/send-message.ts +0 -28
- package/src/tools/suggest-google-business-review-reply.ts +0 -44
- package/src/tools/sync-inbox.ts +0 -28
- package/src/tools/test-webhook.ts +0 -18
- package/src/tools/update-comment.ts +0 -31
- package/src/tools/update-oauth-client.ts +0 -38
- package/src/tools/update-post-release-id.ts +0 -25
- package/src/tools/update-post-status.ts +0 -31
- package/src/tools/update-webhook.ts +0 -36
- package/src/tools/upload-media-from-url.ts +0 -33
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
import { type ToolContext } from '../lib/tool-runtime.js';
|
|
4
|
+
type JobsInput = {
|
|
5
|
+
type: 'image' | 'video';
|
|
6
|
+
job_id?: string;
|
|
7
|
+
status?: string;
|
|
8
|
+
limit?: number;
|
|
9
|
+
};
|
|
10
|
+
export declare const listJobsTool: {
|
|
11
|
+
name: string;
|
|
12
|
+
description: string;
|
|
13
|
+
inputSchema: z.ZodObject<{
|
|
14
|
+
type: z.ZodEnum<["image", "video"]>;
|
|
15
|
+
job_id: z.ZodOptional<z.ZodString>;
|
|
16
|
+
status: z.ZodOptional<z.ZodEnum<["pending", "processing", "completed", "failed", "dismissed"]>>;
|
|
17
|
+
limit: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
|
18
|
+
}, "strip", z.ZodTypeAny, {
|
|
19
|
+
type: "image" | "video";
|
|
20
|
+
status?: "failed" | "pending" | "dismissed" | "completed" | "processing" | undefined;
|
|
21
|
+
limit?: number | undefined;
|
|
22
|
+
job_id?: string | undefined;
|
|
23
|
+
}, {
|
|
24
|
+
type: "image" | "video";
|
|
25
|
+
status?: "failed" | "pending" | "dismissed" | "completed" | "processing" | undefined;
|
|
26
|
+
limit?: number | undefined;
|
|
27
|
+
job_id?: string | undefined;
|
|
28
|
+
}>;
|
|
29
|
+
/** The old tools' exact input schemas, for alias calls (see alias-transport.ts). */
|
|
30
|
+
legacySchemas: {
|
|
31
|
+
get_image_job: z.ZodObject<{
|
|
32
|
+
job_id: z.ZodOptional<z.ZodString>;
|
|
33
|
+
status: z.ZodOptional<z.ZodEnum<["pending", "processing", "completed", "failed"]>>;
|
|
34
|
+
limit: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
|
35
|
+
}, "strip", z.ZodTypeAny, {
|
|
36
|
+
status?: "failed" | "pending" | "completed" | "processing" | undefined;
|
|
37
|
+
limit?: number | undefined;
|
|
38
|
+
job_id?: string | undefined;
|
|
39
|
+
}, {
|
|
40
|
+
status?: "failed" | "pending" | "completed" | "processing" | undefined;
|
|
41
|
+
limit?: number | undefined;
|
|
42
|
+
job_id?: string | undefined;
|
|
43
|
+
}>;
|
|
44
|
+
get_video_job: z.ZodObject<{
|
|
45
|
+
job_id: z.ZodOptional<z.ZodString>;
|
|
46
|
+
status: z.ZodOptional<z.ZodEnum<["pending", "processing", "completed", "failed", "dismissed"]>>;
|
|
47
|
+
limit: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
|
48
|
+
}, "strip", z.ZodTypeAny, {
|
|
49
|
+
status?: "failed" | "pending" | "dismissed" | "completed" | "processing" | undefined;
|
|
50
|
+
limit?: number | undefined;
|
|
51
|
+
job_id?: string | undefined;
|
|
52
|
+
}, {
|
|
53
|
+
status?: "failed" | "pending" | "dismissed" | "completed" | "processing" | undefined;
|
|
54
|
+
limit?: number | undefined;
|
|
55
|
+
job_id?: string | undefined;
|
|
56
|
+
}>;
|
|
57
|
+
};
|
|
58
|
+
execute(client: PosterlyClient, input: JobsInput, ctx: ToolContext): Promise<string>;
|
|
59
|
+
};
|
|
60
|
+
export {};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { validateArgs } from '../lib/tool-runtime.js';
|
|
3
|
+
export const listJobsTool = {
|
|
4
|
+
name: 'list_jobs',
|
|
5
|
+
description: 'AI generation jobs. type=image: one image job by job_id, or recent image jobs when job_id is omitted (filter by status, limit); poll it after generate_image for the finished urls. type=video: one Veo or Grok video job by job_id, or recent video jobs (status includes dismissed, limit); poll it after generate_video for the finished video_url.',
|
|
6
|
+
inputSchema: z.object({
|
|
7
|
+
type: z.enum(['image', 'video']).describe('image or video.'),
|
|
8
|
+
job_id: z.string().optional().describe('One job. Leave out to list recent jobs.'),
|
|
9
|
+
status: z
|
|
10
|
+
.enum(['pending', 'processing', 'completed', 'failed', 'dismissed'])
|
|
11
|
+
.optional()
|
|
12
|
+
.describe('Filter a job list. dismissed is video only.'),
|
|
13
|
+
limit: z.number().int().min(1).max(50).default(10).optional(),
|
|
14
|
+
}),
|
|
15
|
+
/** The old tools' exact input schemas, for alias calls (see alias-transport.ts). */
|
|
16
|
+
legacySchemas: {
|
|
17
|
+
get_image_job: z.object({
|
|
18
|
+
job_id: z.string().optional(),
|
|
19
|
+
status: z.enum(['pending', 'processing', 'completed', 'failed']).optional(),
|
|
20
|
+
limit: z.number().int().min(1).max(50).default(10).optional(),
|
|
21
|
+
}),
|
|
22
|
+
get_video_job: z.object({
|
|
23
|
+
job_id: z.string().optional(),
|
|
24
|
+
status: z.enum(['pending', 'processing', 'completed', 'failed', 'dismissed']).optional(),
|
|
25
|
+
limit: z.number().int().min(1).max(50).default(10).optional(),
|
|
26
|
+
}),
|
|
27
|
+
},
|
|
28
|
+
async execute(client, input, ctx) {
|
|
29
|
+
const { mode, args } = validateArgs(ctx, 'list_jobs', input);
|
|
30
|
+
if (args.job_id) {
|
|
31
|
+
const extra = ['status', 'limit'].filter((key) => args[key] !== undefined);
|
|
32
|
+
if (extra.length) {
|
|
33
|
+
throw new Error(`${extra.join(' and ')} cannot be combined with job_id. Pass job_id alone for one job, or leave it out to list recent jobs.`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const params = { job_id: args.job_id, status: args.status, limit: args.limit };
|
|
37
|
+
return mode === 'video' ? videoJobs(client, params) : imageJobs(client, params);
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
async function imageJobs(client, input) {
|
|
41
|
+
const result = await client.getImageJob(input);
|
|
42
|
+
if (result.job)
|
|
43
|
+
return formatImageJob(result.job, true);
|
|
44
|
+
const jobs = result.jobs || [];
|
|
45
|
+
return [
|
|
46
|
+
`Image jobs (${jobs.length})`,
|
|
47
|
+
jobs.map((job) => formatImageJob(job, false)).join('\n\n'),
|
|
48
|
+
].filter(Boolean).join('\n');
|
|
49
|
+
}
|
|
50
|
+
async function videoJobs(client, input) {
|
|
51
|
+
const result = await client.getVideoJob(input);
|
|
52
|
+
if (result.job)
|
|
53
|
+
return formatVideoJob(result.job, true);
|
|
54
|
+
const jobs = result.jobs || [];
|
|
55
|
+
return [
|
|
56
|
+
`Video jobs (${jobs.length})`,
|
|
57
|
+
jobs.map((job) => formatVideoJob(job, false)).join('\n\n'),
|
|
58
|
+
].filter(Boolean).join('\n');
|
|
59
|
+
}
|
|
60
|
+
function formatImageJob(job, includeRaw) {
|
|
61
|
+
const lines = [
|
|
62
|
+
`${job.id}: ${job.status}`,
|
|
63
|
+
`Prompt: ${job.prompt}`,
|
|
64
|
+
`Model: ${job.model}; resolution: ${job.resolution}; thinking: ${job.thinking_level || 'n/a'}; cost: ${job.credit_cost}`,
|
|
65
|
+
job.urls?.length ? `URLs: ${job.urls.join(', ')}` : null,
|
|
66
|
+
job.error_message ? `Error: ${job.error_message}` : null,
|
|
67
|
+
includeRaw ? `\nRaw job:\n${JSON.stringify(job, null, 2)}` : null,
|
|
68
|
+
];
|
|
69
|
+
return lines.filter(Boolean).join('\n');
|
|
70
|
+
}
|
|
71
|
+
function formatVideoJob(job, includeRaw) {
|
|
72
|
+
const lines = [
|
|
73
|
+
`${job.id}: ${job.status}`,
|
|
74
|
+
`Prompt: ${job.prompt}`,
|
|
75
|
+
`Model: ${job.model}; duration: ${job.duration_seconds}s; resolution: ${job.resolution || 'n/a'}; cost: ${job.credit_cost}`,
|
|
76
|
+
job.video_url ? `Video URL: ${job.video_url}` : null,
|
|
77
|
+
job.error_message ? `Error: ${job.error_message}` : null,
|
|
78
|
+
includeRaw ? `\nRaw job:\n${JSON.stringify(job, null, 2)}` : null,
|
|
79
|
+
];
|
|
80
|
+
return lines.filter(Boolean).join('\n');
|
|
81
|
+
}
|
|
@@ -1,16 +1,75 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
import { type ToolContext } from '../lib/tool-runtime.js';
|
|
4
|
+
type ListPlatformsInput = {
|
|
5
|
+
view?: 'platforms' | 'schema' | 'connect_link';
|
|
6
|
+
include_planned?: boolean;
|
|
7
|
+
account_id?: string;
|
|
8
|
+
platform?: string;
|
|
9
|
+
target?: string;
|
|
10
|
+
workspace_id?: string;
|
|
11
|
+
debug?: boolean;
|
|
12
|
+
};
|
|
3
13
|
export declare const listPlatformsTool: {
|
|
4
14
|
name: string;
|
|
5
15
|
description: string;
|
|
6
16
|
inputSchema: z.ZodObject<{
|
|
17
|
+
view: z.ZodOptional<z.ZodEnum<["platforms", "schema", "connect_link"]>>;
|
|
18
|
+
account_id: z.ZodOptional<z.ZodString>;
|
|
19
|
+
platform: z.ZodOptional<z.ZodEnum<["bluesky", "devto", "discord", "facebook", "gmb", "google-business", "google_business", "google_business_profile", "hashnode", "instagram", "instagram-standalone", "lemmy", "linkedin", "mastodon", "medium", "pinterest", "reddit", "skool", "slack", "telegram", "threads", "tiktok", "twitter", "whop", "wordpress", "x", "youtube"]>>;
|
|
20
|
+
target: z.ZodOptional<z.ZodEnum<["bluesky", "devto", "discord", "facebook", "facebook_instagram", "facebook_pages", "gmb", "google-business", "google_business", "google_business_profile", "hashnode", "instagram", "instagram-standalone", "instagram_direct", "lemmy", "linkedin", "linkedin-company", "linkedin-page", "linkedin_company", "linkedin_page", "linkedin_personal", "mastodon", "medium", "meta", "meta_business", "pinterest", "reddit", "skool", "slack", "telegram", "threads", "tiktok", "twitter", "whop", "wordpress", "x", "x_twitter", "youtube"]>>;
|
|
21
|
+
workspace_id: z.ZodOptional<z.ZodString>;
|
|
7
22
|
include_planned: z.ZodOptional<z.ZodBoolean>;
|
|
23
|
+
debug: z.ZodOptional<z.ZodBoolean>;
|
|
8
24
|
}, "strip", z.ZodTypeAny, {
|
|
25
|
+
platform?: "instagram" | "instagram-standalone" | "facebook" | "tiktok" | "twitter" | "threads" | "linkedin" | "youtube" | "pinterest" | "google_business" | "medium" | "x" | "telegram" | "bluesky" | "discord" | "wordpress" | "devto" | "hashnode" | "lemmy" | "slack" | "mastodon" | "reddit" | "skool" | "whop" | "gmb" | "google-business" | "google_business_profile" | undefined;
|
|
26
|
+
workspace_id?: string | undefined;
|
|
9
27
|
include_planned?: boolean | undefined;
|
|
28
|
+
account_id?: string | undefined;
|
|
29
|
+
view?: "platforms" | "schema" | "connect_link" | undefined;
|
|
30
|
+
debug?: boolean | undefined;
|
|
31
|
+
target?: "meta" | "instagram_direct" | "instagram" | "instagram-standalone" | "facebook" | "tiktok" | "twitter" | "threads" | "linkedin" | "youtube" | "pinterest" | "google_business" | "medium" | "x" | "telegram" | "bluesky" | "discord" | "wordpress" | "devto" | "hashnode" | "lemmy" | "slack" | "mastodon" | "reddit" | "skool" | "whop" | "gmb" | "google-business" | "google_business_profile" | "linkedin_page" | "facebook_instagram" | "facebook_pages" | "linkedin-company" | "linkedin-page" | "linkedin_company" | "linkedin_personal" | "meta_business" | "x_twitter" | undefined;
|
|
10
32
|
}, {
|
|
33
|
+
platform?: "instagram" | "instagram-standalone" | "facebook" | "tiktok" | "twitter" | "threads" | "linkedin" | "youtube" | "pinterest" | "google_business" | "medium" | "x" | "telegram" | "bluesky" | "discord" | "wordpress" | "devto" | "hashnode" | "lemmy" | "slack" | "mastodon" | "reddit" | "skool" | "whop" | "gmb" | "google-business" | "google_business_profile" | undefined;
|
|
34
|
+
workspace_id?: string | undefined;
|
|
11
35
|
include_planned?: boolean | undefined;
|
|
36
|
+
account_id?: string | undefined;
|
|
37
|
+
view?: "platforms" | "schema" | "connect_link" | undefined;
|
|
38
|
+
debug?: boolean | undefined;
|
|
39
|
+
target?: "meta" | "instagram_direct" | "instagram" | "instagram-standalone" | "facebook" | "tiktok" | "twitter" | "threads" | "linkedin" | "youtube" | "pinterest" | "google_business" | "medium" | "x" | "telegram" | "bluesky" | "discord" | "wordpress" | "devto" | "hashnode" | "lemmy" | "slack" | "mastodon" | "reddit" | "skool" | "whop" | "gmb" | "google-business" | "google_business_profile" | "linkedin_page" | "facebook_instagram" | "facebook_pages" | "linkedin-company" | "linkedin-page" | "linkedin_company" | "linkedin_personal" | "meta_business" | "x_twitter" | undefined;
|
|
12
40
|
}>;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
41
|
+
/** The old tools' exact input schemas, for alias calls (see alias-transport.ts). */
|
|
42
|
+
legacySchemas: {
|
|
43
|
+
get_platform_schema: z.ZodObject<{
|
|
44
|
+
account_id: z.ZodOptional<z.ZodString>;
|
|
45
|
+
platform: z.ZodOptional<z.ZodEnum<["bluesky", "devto", "discord", "facebook", "gmb", "google-business", "google_business", "google_business_profile", "hashnode", "instagram", "instagram-standalone", "lemmy", "linkedin", "mastodon", "medium", "pinterest", "reddit", "skool", "slack", "telegram", "threads", "tiktok", "twitter", "whop", "wordpress", "x", "youtube"]>>;
|
|
46
|
+
include_planned: z.ZodOptional<z.ZodBoolean>;
|
|
47
|
+
}, "strip", z.ZodTypeAny, {
|
|
48
|
+
platform?: "instagram" | "instagram-standalone" | "facebook" | "tiktok" | "twitter" | "threads" | "linkedin" | "youtube" | "pinterest" | "google_business" | "medium" | "x" | "telegram" | "bluesky" | "discord" | "wordpress" | "devto" | "hashnode" | "lemmy" | "slack" | "mastodon" | "reddit" | "skool" | "whop" | "gmb" | "google-business" | "google_business_profile" | undefined;
|
|
49
|
+
include_planned?: boolean | undefined;
|
|
50
|
+
account_id?: string | undefined;
|
|
51
|
+
}, {
|
|
52
|
+
platform?: "instagram" | "instagram-standalone" | "facebook" | "tiktok" | "twitter" | "threads" | "linkedin" | "youtube" | "pinterest" | "google_business" | "medium" | "x" | "telegram" | "bluesky" | "discord" | "wordpress" | "devto" | "hashnode" | "lemmy" | "slack" | "mastodon" | "reddit" | "skool" | "whop" | "gmb" | "google-business" | "google_business_profile" | undefined;
|
|
53
|
+
include_planned?: boolean | undefined;
|
|
54
|
+
account_id?: string | undefined;
|
|
55
|
+
}>;
|
|
56
|
+
get_connect_link: z.ZodObject<{
|
|
57
|
+
platform: z.ZodOptional<z.ZodEnum<["bluesky", "devto", "discord", "facebook", "facebook_instagram", "facebook_pages", "gmb", "google-business", "google_business", "google_business_profile", "hashnode", "instagram", "instagram-standalone", "instagram_direct", "lemmy", "linkedin", "linkedin-company", "linkedin-page", "linkedin_company", "linkedin_page", "linkedin_personal", "mastodon", "medium", "meta", "meta_business", "pinterest", "reddit", "skool", "slack", "telegram", "threads", "tiktok", "twitter", "whop", "wordpress", "x", "x_twitter", "youtube"]>>;
|
|
58
|
+
workspace_id: z.ZodOptional<z.ZodString>;
|
|
59
|
+
include_planned: z.ZodOptional<z.ZodBoolean>;
|
|
60
|
+
debug: z.ZodOptional<z.ZodBoolean>;
|
|
61
|
+
}, "strip", z.ZodTypeAny, {
|
|
62
|
+
platform?: "meta" | "instagram_direct" | "instagram" | "instagram-standalone" | "facebook" | "tiktok" | "twitter" | "threads" | "linkedin" | "youtube" | "pinterest" | "google_business" | "medium" | "x" | "telegram" | "bluesky" | "discord" | "wordpress" | "devto" | "hashnode" | "lemmy" | "slack" | "mastodon" | "reddit" | "skool" | "whop" | "gmb" | "google-business" | "google_business_profile" | "linkedin_page" | "facebook_instagram" | "facebook_pages" | "linkedin-company" | "linkedin-page" | "linkedin_company" | "linkedin_personal" | "meta_business" | "x_twitter" | undefined;
|
|
63
|
+
workspace_id?: string | undefined;
|
|
64
|
+
include_planned?: boolean | undefined;
|
|
65
|
+
debug?: boolean | undefined;
|
|
66
|
+
}, {
|
|
67
|
+
platform?: "meta" | "instagram_direct" | "instagram" | "instagram-standalone" | "facebook" | "tiktok" | "twitter" | "threads" | "linkedin" | "youtube" | "pinterest" | "google_business" | "medium" | "x" | "telegram" | "bluesky" | "discord" | "wordpress" | "devto" | "hashnode" | "lemmy" | "slack" | "mastodon" | "reddit" | "skool" | "whop" | "gmb" | "google-business" | "google_business_profile" | "linkedin_page" | "facebook_instagram" | "facebook_pages" | "linkedin-company" | "linkedin-page" | "linkedin_company" | "linkedin_personal" | "meta_business" | "x_twitter" | undefined;
|
|
68
|
+
workspace_id?: string | undefined;
|
|
69
|
+
include_planned?: boolean | undefined;
|
|
70
|
+
debug?: boolean | undefined;
|
|
71
|
+
}>;
|
|
72
|
+
};
|
|
73
|
+
execute(client: PosterlyClient, input: ListPlatformsInput, ctx: ToolContext): Promise<string>;
|
|
16
74
|
};
|
|
75
|
+
export {};
|
|
@@ -1,20 +1,129 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { PLANNED_PLATFORM_IDS } from '../generated/platform-manifest.js';
|
|
2
|
+
import { ALL_PLATFORM_INPUTS, CONNECT_INPUTS, PLANNED_PLATFORM_IDS, SUPPORTED_PLATFORM_IDS } from '../generated/platform-manifest.js';
|
|
3
|
+
import { validateArgs } from '../lib/tool-runtime.js';
|
|
3
4
|
export const listPlatformsTool = {
|
|
4
5
|
name: 'list_platforms',
|
|
5
|
-
description: '
|
|
6
|
+
description: 'Platforms, settings schemas, and connection links. view=platforms (default): posterly platform integrations, posting capabilities, content/media limits, settings schemas, helper tools, and analytics support (include_planned shows future integration possibilities). view=schema: the settings schema for one connected account_id (preferred: returns connection-specific capabilities, needed before Instagram native tags/collaborators) or one platform; account_id wins if both are given. view=connect_link: dashboard handoff links and readiness for every target, or one target (instagram, meta, linkedin_page, twitter, telegram, reddit, wordpress, ...); use connection_url in a logged-in browser (direct OAuth URLs are intentionally not exposed); credential platforms show the credential_fields that connect_account needs.',
|
|
6
7
|
inputSchema: z.object({
|
|
8
|
+
view: z
|
|
9
|
+
.enum(['platforms', 'schema', 'connect_link'])
|
|
10
|
+
.optional()
|
|
11
|
+
.describe('platforms (default), schema, or connect_link.'),
|
|
12
|
+
account_id: z
|
|
13
|
+
.string()
|
|
14
|
+
.optional()
|
|
15
|
+
.describe('view=schema: connected account ID from list_accounts. Preferred because it returns account context.'),
|
|
16
|
+
platform: z
|
|
17
|
+
.enum(ALL_PLATFORM_INPUTS)
|
|
18
|
+
.optional()
|
|
19
|
+
.describe(`view=schema: platform ID such as ${SUPPORTED_PLATFORM_IDS.join(', ')}. Set include_planned to inspect planned providers.`),
|
|
20
|
+
target: z
|
|
21
|
+
.enum(CONNECT_INPUTS)
|
|
22
|
+
.optional()
|
|
23
|
+
.describe('view=connect_link: connection target such as instagram, meta, linkedin_page, twitter, x, google_business, telegram, reddit, or wordpress. Omit to list live connection targets.'),
|
|
24
|
+
workspace_id: z
|
|
25
|
+
.string()
|
|
26
|
+
.optional()
|
|
27
|
+
.describe('view=connect_link: filter connected account counts to a workspace.'),
|
|
7
28
|
include_planned: z
|
|
8
29
|
.boolean()
|
|
9
30
|
.optional()
|
|
10
31
|
.describe(`Include planned integrations such as ${PLANNED_PLATFORM_IDS.join(', ')}.`),
|
|
32
|
+
debug: z
|
|
33
|
+
.boolean()
|
|
34
|
+
.optional()
|
|
35
|
+
.describe('view=connect_link: when true, include the raw connect option JSON for debugging. Keep false for normal user-facing agent flows.'),
|
|
11
36
|
}),
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
37
|
+
/** The old tools' exact input schemas, for alias calls (see alias-transport.ts). */
|
|
38
|
+
legacySchemas: {
|
|
39
|
+
get_platform_schema: z.object({
|
|
40
|
+
account_id: z.string().optional(),
|
|
41
|
+
platform: z.enum(ALL_PLATFORM_INPUTS).optional(),
|
|
42
|
+
include_planned: z.boolean().optional(),
|
|
43
|
+
}),
|
|
44
|
+
get_connect_link: z.object({
|
|
45
|
+
platform: z.enum(CONNECT_INPUTS).optional(),
|
|
46
|
+
workspace_id: z.string().optional(),
|
|
47
|
+
include_planned: z.boolean().optional(),
|
|
48
|
+
debug: z.boolean().optional(),
|
|
49
|
+
}),
|
|
50
|
+
},
|
|
51
|
+
async execute(client, input, ctx) {
|
|
52
|
+
const { mode, args } = validateArgs(ctx, 'list_platforms', input);
|
|
53
|
+
if (mode === 'schema')
|
|
54
|
+
return platformSchema(client, args);
|
|
55
|
+
if (mode === 'connect_link')
|
|
56
|
+
return connectLink(client, args);
|
|
57
|
+
return platforms(client, args);
|
|
19
58
|
},
|
|
20
59
|
};
|
|
60
|
+
async function platforms(client, input) {
|
|
61
|
+
const result = await client.listPlatforms({ include_planned: input.include_planned });
|
|
62
|
+
const lines = result.platforms.map((platform) => {
|
|
63
|
+
const helperCount = platform.helper_tools?.length || 0;
|
|
64
|
+
return `• ${platform.label} (${platform.id}): ${platform.status}; post types: ${platform.post_types.join(', ') || 'n/a'}; helpers: ${helperCount}; analytics: ${platform.analytics_supported ? 'yes' : 'no'}`;
|
|
65
|
+
});
|
|
66
|
+
return `posterly platforms (${result.platforms.length}):\n${lines.join('\n')}`;
|
|
67
|
+
}
|
|
68
|
+
async function platformSchema(client, input) {
|
|
69
|
+
const result = await client.getPlatformSchema({ account_id: input.account_id, platform: input.platform, include_planned: input.include_planned });
|
|
70
|
+
const schema = result.schema || result.platform || result.platforms?.[0];
|
|
71
|
+
if (!schema)
|
|
72
|
+
return JSON.stringify(result, null, 2);
|
|
73
|
+
const fields = schema.settings_schema?.fields || [];
|
|
74
|
+
const helpers = schema.helper_tools || [];
|
|
75
|
+
const accountLine = result.account
|
|
76
|
+
? `Account: ${result.account.username || result.account.id} (${result.account.platform})\n`
|
|
77
|
+
: '';
|
|
78
|
+
const instagramTaggingLine = result.account?.instagram_tagging
|
|
79
|
+
? `Instagram tagging capabilities: ${JSON.stringify(result.account.instagram_tagging)}`
|
|
80
|
+
: '';
|
|
81
|
+
return [
|
|
82
|
+
`${schema.label} (${schema.id}) schema`,
|
|
83
|
+
accountLine.trim(),
|
|
84
|
+
instagramTaggingLine,
|
|
85
|
+
`Status: ${schema.status}`,
|
|
86
|
+
`Post types: ${schema.post_types.join(', ') || 'n/a'}`,
|
|
87
|
+
`Content limit: ${schema.content_limit ?? 'n/a'}`,
|
|
88
|
+
`Media: ${JSON.stringify(schema.media)}`,
|
|
89
|
+
`Analytics: ${schema.analytics_supported ? 'yes' : 'no'}`,
|
|
90
|
+
fields.length
|
|
91
|
+
? `Settings:\n${fields.map((field) => `• ${field.key}${field.required ? ' (required)' : ''}: ${field.description}`).join('\n')}`
|
|
92
|
+
: 'Settings: none',
|
|
93
|
+
helpers.length
|
|
94
|
+
? `Helpers:\n${helpers.map((helper) => `• ${helper.name}: ${helper.description}`).join('\n')}`
|
|
95
|
+
: 'Helpers: none',
|
|
96
|
+
`Example settings: ${JSON.stringify(schema.settings_schema?.example || {})}`,
|
|
97
|
+
].filter(Boolean).join('\n');
|
|
98
|
+
}
|
|
99
|
+
async function connectLink(client, input) {
|
|
100
|
+
const { debug } = input;
|
|
101
|
+
const result = await client.getConnectLink({
|
|
102
|
+
platform: input.target,
|
|
103
|
+
workspace_id: input.workspace_id,
|
|
104
|
+
include_planned: input.include_planned,
|
|
105
|
+
});
|
|
106
|
+
if (result.connect) {
|
|
107
|
+
return formatConnectOption(result.connect, Boolean(debug));
|
|
108
|
+
}
|
|
109
|
+
const options = result.connect_options || [];
|
|
110
|
+
const lines = options.map((option) => formatConnectOption(option, false));
|
|
111
|
+
return `posterly connection options (${options.length}):\n${lines.join('\n\n')}`;
|
|
112
|
+
}
|
|
113
|
+
function formatConnectOption(option, includeRaw) {
|
|
114
|
+
const missing = option.missing_env?.length
|
|
115
|
+
? `missing env: ${option.missing_env.map((group) => group.join(' or ')).join(', ')}`
|
|
116
|
+
: 'configured';
|
|
117
|
+
const accounts = option.connected_count ?? option.connected_accounts?.length ?? 0;
|
|
118
|
+
const fields = option.credential_fields?.length
|
|
119
|
+
? `; credential fields: ${option.credential_fields.map((field) => field.key).join(', ')}`
|
|
120
|
+
: '';
|
|
121
|
+
const scopes = option.scopes?.length ? `; scopes: ${option.scopes.join(', ')}` : '';
|
|
122
|
+
const raw = includeRaw ? `\n\nRaw connect option:\n${JSON.stringify(option, null, 2)}` : '';
|
|
123
|
+
return [
|
|
124
|
+
`${option.label} (${option.platform})`,
|
|
125
|
+
`Status: ${option.status}; method: ${option.method}; ${missing}; connected accounts: ${accounts}`,
|
|
126
|
+
`Connection URL: ${option.connection_url || 'not available'}${fields}${scopes}`,
|
|
127
|
+
raw,
|
|
128
|
+
].join('\n');
|
|
129
|
+
}
|
|
@@ -12,7 +12,7 @@ export declare const listPostsTool: {
|
|
|
12
12
|
approval_status: z.ZodOptional<z.ZodEnum<["none", "pending_client", "approved", "changes_requested", "rejected"]>>;
|
|
13
13
|
brand_id: z.ZodOptional<z.ZodString>;
|
|
14
14
|
}, "strip", z.ZodTypeAny, {
|
|
15
|
-
platform?: "instagram" | "instagram-standalone" | "facebook" | "tiktok" | "twitter" | "threads" | "linkedin" | "youtube" | "pinterest" | "google_business" | "x" | "telegram" | "bluesky" | "discord" | "
|
|
15
|
+
platform?: "instagram" | "instagram-standalone" | "facebook" | "tiktok" | "twitter" | "threads" | "linkedin" | "youtube" | "pinterest" | "google_business" | "x" | "telegram" | "bluesky" | "discord" | "wordpress" | "devto" | "hashnode" | "lemmy" | "slack" | "mastodon" | "gmb" | "google-business" | "google_business_profile" | undefined;
|
|
16
16
|
status?: string | undefined;
|
|
17
17
|
workspace_id?: string | undefined;
|
|
18
18
|
account_id?: string | undefined;
|
|
@@ -20,7 +20,7 @@ export declare const listPostsTool: {
|
|
|
20
20
|
approval_status?: "none" | "pending_client" | "approved" | "changes_requested" | "rejected" | undefined;
|
|
21
21
|
brand_id?: string | undefined;
|
|
22
22
|
}, {
|
|
23
|
-
platform?: "instagram" | "instagram-standalone" | "facebook" | "tiktok" | "twitter" | "threads" | "linkedin" | "youtube" | "pinterest" | "google_business" | "x" | "telegram" | "bluesky" | "discord" | "
|
|
23
|
+
platform?: "instagram" | "instagram-standalone" | "facebook" | "tiktok" | "twitter" | "threads" | "linkedin" | "youtube" | "pinterest" | "google_business" | "x" | "telegram" | "bluesky" | "discord" | "wordpress" | "devto" | "hashnode" | "lemmy" | "slack" | "mastodon" | "gmb" | "google-business" | "google_business_profile" | undefined;
|
|
24
24
|
status?: string | undefined;
|
|
25
25
|
workspace_id?: string | undefined;
|
|
26
26
|
account_id?: string | undefined;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
import { type ToolContext } from '../lib/tool-runtime.js';
|
|
4
|
+
type ManageCommentInput = {
|
|
5
|
+
action: 'reply' | 'update' | 'delete';
|
|
6
|
+
comment_id: string;
|
|
7
|
+
content?: string;
|
|
8
|
+
type?: 'public' | 'private';
|
|
9
|
+
is_hidden?: boolean;
|
|
10
|
+
is_read?: boolean;
|
|
11
|
+
workspace_id?: string;
|
|
12
|
+
confirm?: boolean;
|
|
13
|
+
preview_id?: string;
|
|
14
|
+
};
|
|
15
|
+
export declare const manageCommentTool: {
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
inputSchema: z.ZodObject<{
|
|
19
|
+
action: z.ZodEnum<["reply", "update", "delete"]>;
|
|
20
|
+
comment_id: z.ZodString;
|
|
21
|
+
content: z.ZodOptional<z.ZodString>;
|
|
22
|
+
type: z.ZodOptional<z.ZodEnum<["public", "private"]>>;
|
|
23
|
+
is_hidden: z.ZodOptional<z.ZodBoolean>;
|
|
24
|
+
is_read: z.ZodOptional<z.ZodBoolean>;
|
|
25
|
+
workspace_id: z.ZodOptional<z.ZodString>;
|
|
26
|
+
confirm: z.ZodOptional<z.ZodBoolean>;
|
|
27
|
+
preview_id: z.ZodOptional<z.ZodString>;
|
|
28
|
+
}, "strip", z.ZodTypeAny, {
|
|
29
|
+
action: "update" | "delete" | "reply";
|
|
30
|
+
comment_id: string;
|
|
31
|
+
confirm?: boolean | undefined;
|
|
32
|
+
preview_id?: string | undefined;
|
|
33
|
+
workspace_id?: string | undefined;
|
|
34
|
+
type?: "public" | "private" | undefined;
|
|
35
|
+
content?: string | undefined;
|
|
36
|
+
is_hidden?: boolean | undefined;
|
|
37
|
+
is_read?: boolean | undefined;
|
|
38
|
+
}, {
|
|
39
|
+
action: "update" | "delete" | "reply";
|
|
40
|
+
comment_id: string;
|
|
41
|
+
confirm?: boolean | undefined;
|
|
42
|
+
preview_id?: string | undefined;
|
|
43
|
+
workspace_id?: string | undefined;
|
|
44
|
+
type?: "public" | "private" | undefined;
|
|
45
|
+
content?: string | undefined;
|
|
46
|
+
is_hidden?: boolean | undefined;
|
|
47
|
+
is_read?: boolean | undefined;
|
|
48
|
+
}>;
|
|
49
|
+
/** The old tools' exact input schemas, for alias calls (see alias-transport.ts). */
|
|
50
|
+
legacySchemas: {
|
|
51
|
+
reply_to_comment: z.ZodObject<{
|
|
52
|
+
comment_id: z.ZodString;
|
|
53
|
+
content: z.ZodString;
|
|
54
|
+
type: z.ZodOptional<z.ZodEnum<["public", "private"]>>;
|
|
55
|
+
workspace_id: z.ZodOptional<z.ZodString>;
|
|
56
|
+
confirm: z.ZodLiteral<true>;
|
|
57
|
+
}, "strip", z.ZodTypeAny, {
|
|
58
|
+
confirm: true;
|
|
59
|
+
content: string;
|
|
60
|
+
comment_id: string;
|
|
61
|
+
workspace_id?: string | undefined;
|
|
62
|
+
type?: "public" | "private" | undefined;
|
|
63
|
+
}, {
|
|
64
|
+
confirm: true;
|
|
65
|
+
content: string;
|
|
66
|
+
comment_id: string;
|
|
67
|
+
workspace_id?: string | undefined;
|
|
68
|
+
type?: "public" | "private" | undefined;
|
|
69
|
+
}>;
|
|
70
|
+
update_comment: z.ZodObject<{
|
|
71
|
+
comment_id: z.ZodString;
|
|
72
|
+
is_hidden: z.ZodOptional<z.ZodBoolean>;
|
|
73
|
+
is_read: z.ZodOptional<z.ZodBoolean>;
|
|
74
|
+
workspace_id: z.ZodOptional<z.ZodString>;
|
|
75
|
+
}, "strip", z.ZodTypeAny, {
|
|
76
|
+
comment_id: string;
|
|
77
|
+
workspace_id?: string | undefined;
|
|
78
|
+
is_hidden?: boolean | undefined;
|
|
79
|
+
is_read?: boolean | undefined;
|
|
80
|
+
}, {
|
|
81
|
+
comment_id: string;
|
|
82
|
+
workspace_id?: string | undefined;
|
|
83
|
+
is_hidden?: boolean | undefined;
|
|
84
|
+
is_read?: boolean | undefined;
|
|
85
|
+
}>;
|
|
86
|
+
delete_comment: z.ZodObject<{
|
|
87
|
+
comment_id: z.ZodString;
|
|
88
|
+
workspace_id: z.ZodOptional<z.ZodString>;
|
|
89
|
+
confirm: z.ZodLiteral<true>;
|
|
90
|
+
}, "strip", z.ZodTypeAny, {
|
|
91
|
+
confirm: true;
|
|
92
|
+
comment_id: string;
|
|
93
|
+
workspace_id?: string | undefined;
|
|
94
|
+
}, {
|
|
95
|
+
confirm: true;
|
|
96
|
+
comment_id: string;
|
|
97
|
+
workspace_id?: string | undefined;
|
|
98
|
+
}>;
|
|
99
|
+
};
|
|
100
|
+
execute(client: PosterlyClient, input: ManageCommentInput, ctx: ToolContext): Promise<string>;
|
|
101
|
+
};
|
|
102
|
+
export {};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { code, mdKeyValue, mdQuote, mdSection } from '../lib/format.js';
|
|
3
|
+
import { previewThenConfirm, readFailedNote, readForPreview, validateArgs } from '../lib/tool-runtime.js';
|
|
4
|
+
export const manageCommentTool = {
|
|
5
|
+
name: 'manage_comment',
|
|
6
|
+
description: 'Act on an inbox comment (Pro plan or higher plus posts:write). action=reply (comment_id, content): reply to an Instagram, Facebook Page, Threads, or LinkedIn Page comment; type private is Instagram only, the others take public replies only. action=update (comment_id, is_hidden and/or is_read): hide or unhide it on the platform, or mark it read or unread; reversible, no confirm needed. action=delete (comment_id): delete an Instagram or Facebook Page comment, irreversible and admin only; Threads replies cannot be deleted, hide them instead. reply and delete use preview then confirm: call without confirm to get a preview and preview_id, show it, then call again with confirm=true and that preview_id.',
|
|
7
|
+
inputSchema: z.object({
|
|
8
|
+
action: z.enum(['reply', 'update', 'delete']).describe('reply, update, or delete.'),
|
|
9
|
+
comment_id: z.string().min(1).describe('Comment ID from list_comments.'),
|
|
10
|
+
content: z.string().min(1).optional().describe('reply: reply text to post.'),
|
|
11
|
+
type: z.enum(['public', 'private']).optional().describe('reply: public (default) or private. Private is Instagram only.'),
|
|
12
|
+
is_hidden: z.boolean().optional().describe('update: hide or unhide the comment on Instagram, Facebook, or Threads.'),
|
|
13
|
+
is_read: z.boolean().optional().describe('update: mark the comment read or unread in posterly.'),
|
|
14
|
+
workspace_id: z.string().optional().describe('Optional. Omit to search every workspace you belong to; pass a workspace ID from whoami to limit to one.'),
|
|
15
|
+
confirm: z.boolean().optional().describe('reply and delete: leave out to get a preview; true only with the preview_id after the user approved it.'),
|
|
16
|
+
preview_id: z.string().optional().describe('reply and delete: the preview_id from the preview call. Required with confirm: true.'),
|
|
17
|
+
}),
|
|
18
|
+
/** The old tools' exact input schemas, for alias calls (see alias-transport.ts). */
|
|
19
|
+
legacySchemas: {
|
|
20
|
+
reply_to_comment: z.object({
|
|
21
|
+
comment_id: z.string().min(1),
|
|
22
|
+
content: z.string().min(1),
|
|
23
|
+
type: z.enum(['public', 'private']).optional(),
|
|
24
|
+
workspace_id: z.string().optional(),
|
|
25
|
+
confirm: z.literal(true),
|
|
26
|
+
}),
|
|
27
|
+
update_comment: z.object({
|
|
28
|
+
comment_id: z.string().min(1),
|
|
29
|
+
is_hidden: z.boolean().optional(),
|
|
30
|
+
is_read: z.boolean().optional(),
|
|
31
|
+
workspace_id: z.string().optional(),
|
|
32
|
+
}),
|
|
33
|
+
delete_comment: z.object({
|
|
34
|
+
comment_id: z.string().min(1),
|
|
35
|
+
workspace_id: z.string().optional(),
|
|
36
|
+
confirm: z.literal(true),
|
|
37
|
+
}),
|
|
38
|
+
},
|
|
39
|
+
async execute(client, input, ctx) {
|
|
40
|
+
const { mode, args } = validateArgs(ctx, 'manage_comment', input);
|
|
41
|
+
if (mode === 'update')
|
|
42
|
+
return updateComment(client, args);
|
|
43
|
+
if (mode === 'delete') {
|
|
44
|
+
return previewThenConfirm({
|
|
45
|
+
tool: 'manage_comment',
|
|
46
|
+
action: 'delete',
|
|
47
|
+
args,
|
|
48
|
+
nonce: false,
|
|
49
|
+
legacyRefusal: 'Refusing to delete comment without confirm=true after explicit user confirmation.',
|
|
50
|
+
ctx,
|
|
51
|
+
describe: async () => [
|
|
52
|
+
await describeComment(client, args),
|
|
53
|
+
'Deletes this comment from the posterly inbox and, on Instagram or Facebook, from the network. This cannot be undone. Threads replies cannot be deleted; hide them with action=update instead.',
|
|
54
|
+
].join('\n\n'),
|
|
55
|
+
run: () => deleteComment(client, args),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return previewThenConfirm({
|
|
59
|
+
tool: 'manage_comment',
|
|
60
|
+
action: 'reply',
|
|
61
|
+
args,
|
|
62
|
+
nonce: true,
|
|
63
|
+
legacyRefusal: 'Refusing to reply to a comment without confirm=true after explicit user confirmation.',
|
|
64
|
+
ctx,
|
|
65
|
+
describe: async () => [
|
|
66
|
+
await describeComment(client, args),
|
|
67
|
+
mdSection(`Reply to post (${args.type === 'private' ? 'private' : 'public'})`, mdQuote(String(args.content ?? ''))),
|
|
68
|
+
'This posts on the social network as your account.',
|
|
69
|
+
].join('\n\n'),
|
|
70
|
+
run: () => replyToComment(client, args),
|
|
71
|
+
});
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
async function describeComment(client, input) {
|
|
75
|
+
const read = await readForPreview(() => client.getComment({ comment_id: input.comment_id, workspace_id: input.workspace_id }));
|
|
76
|
+
if (!read.ok) {
|
|
77
|
+
return [readFailedNote(read.error), mdKeyValue([['Comment ID', code(input.comment_id)], ['Workspace', input.workspace_id ? code(input.workspace_id) : undefined]])].join('\n\n');
|
|
78
|
+
}
|
|
79
|
+
const comment = read.data.comment;
|
|
80
|
+
return mdSection('Comment', mdKeyValue([
|
|
81
|
+
['Comment ID', code(String(comment.id))],
|
|
82
|
+
['Platform', typeof comment.platform === 'string' ? comment.platform : 'unknown'],
|
|
83
|
+
['Author', typeof comment.author_username === 'string' ? `@${comment.author_username}` : 'unknown'],
|
|
84
|
+
['Content', typeof comment.content === 'string' ? comment.content : '(empty)'],
|
|
85
|
+
]));
|
|
86
|
+
}
|
|
87
|
+
async function replyToComment(client, input) {
|
|
88
|
+
const result = await client.replyToComment({
|
|
89
|
+
comment_id: input.comment_id,
|
|
90
|
+
content: input.content,
|
|
91
|
+
type: input.type,
|
|
92
|
+
workspace_id: input.workspace_id,
|
|
93
|
+
});
|
|
94
|
+
return `Comment reply sent (${result.reply_type}, reply_id ${result.reply_id}).`;
|
|
95
|
+
}
|
|
96
|
+
async function updateComment(client, input) {
|
|
97
|
+
const result = await client.updateComment({
|
|
98
|
+
comment_id: input.comment_id,
|
|
99
|
+
is_hidden: input.is_hidden,
|
|
100
|
+
is_read: input.is_read,
|
|
101
|
+
workspace_id: input.workspace_id,
|
|
102
|
+
});
|
|
103
|
+
const comment = result.comment;
|
|
104
|
+
const parts = [`Comment ${String(comment.id)} updated.`];
|
|
105
|
+
if (typeof comment.is_hidden === 'boolean')
|
|
106
|
+
parts.push(`Hidden: ${comment.is_hidden ? 'yes' : 'no'}.`);
|
|
107
|
+
if (typeof comment.is_read === 'boolean')
|
|
108
|
+
parts.push(`Read: ${comment.is_read ? 'yes' : 'no'}.`);
|
|
109
|
+
return parts.join(' ');
|
|
110
|
+
}
|
|
111
|
+
async function deleteComment(client, input) {
|
|
112
|
+
if (input.confirm !== true) {
|
|
113
|
+
throw new Error('Refusing to delete comment without confirm=true after explicit user confirmation.');
|
|
114
|
+
}
|
|
115
|
+
await client.deleteComment(input.comment_id, input.workspace_id);
|
|
116
|
+
// Output kept byte-identical to the old delete_comment tool (its alias
|
|
117
|
+
// must match); the old name in the next-step line still works until the
|
|
118
|
+
// alias sunset.
|
|
119
|
+
return [
|
|
120
|
+
`Comment ${input.comment_id} deleted successfully.`,
|
|
121
|
+
'It has been deleted from the posterly inbox. On Instagram or Facebook it is also removed on the network when the platform call succeeds.',
|
|
122
|
+
'',
|
|
123
|
+
'Next step for the AI agent: tell the user the comment is gone. Threads replies cannot be deleted; hide them with update_comment instead.',
|
|
124
|
+
].join('\n');
|
|
125
|
+
}
|