posterly-mcp-server 0.19.1 → 0.19.2
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 +3 -1
- package/dist/index.js +50 -49
- package/dist/lib/api-client.js +1 -1
- package/dist/lib/format.d.ts +21 -0
- package/dist/lib/format.js +125 -0
- package/dist/tools/audit-google-business-profile.js +15 -12
- package/dist/tools/create-oauth-client.js +7 -1
- package/dist/tools/create-post.js +20 -27
- package/dist/tools/create-posts-batch.js +23 -15
- package/dist/tools/create-signed-upload.js +11 -8
- package/dist/tools/create-webhook.js +7 -2
- package/dist/tools/delete-google-business-review-reply.d.ts +1 -1
- package/dist/tools/delete-google-business-review-reply.js +4 -1
- package/dist/tools/delete-oauth-client.js +4 -1
- package/dist/tools/delete-post-group.js +5 -1
- package/dist/tools/delete-post.js +4 -1
- package/dist/tools/delete-webhook.js +4 -1
- package/dist/tools/disconnect-account.js +7 -5
- package/dist/tools/find-slot.js +10 -3
- package/dist/tools/generate-image.js +17 -19
- package/dist/tools/generate-video.js +11 -9
- package/dist/tools/get-account-analytics.js +64 -45
- package/dist/tools/get-brand-profile.js +34 -40
- package/dist/tools/get-brand.js +14 -16
- package/dist/tools/get-connect-link.js +26 -7
- package/dist/tools/get-google-business-review-link.js +6 -6
- package/dist/tools/get-platform-schema.js +23 -16
- package/dist/tools/get-post-analytics.js +53 -50
- package/dist/tools/get-post-missing.js +5 -1
- package/dist/tools/get-post.js +16 -14
- package/dist/tools/get-video-job.d.ts +2 -2
- package/dist/tools/get-video-job.js +28 -11
- package/dist/tools/get-video-options.js +21 -15
- package/dist/tools/get-x-posting-quota.js +12 -9
- package/dist/tools/list-accounts.js +12 -4
- package/dist/tools/list-activity.js +13 -18
- package/dist/tools/list-brand-accounts.js +11 -3
- package/dist/tools/list-brands.js +12 -11
- package/dist/tools/list-google-business-reviews.js +13 -11
- package/dist/tools/list-oauth-clients.js +10 -4
- package/dist/tools/list-platforms.js +12 -5
- package/dist/tools/list-posts.js +12 -7
- package/dist/tools/list-webhooks.js +13 -11
- package/dist/tools/reply-google-business-review.d.ts +1 -1
- package/dist/tools/reply-google-business-review.js +4 -1
- package/dist/tools/run-video-function.js +4 -4
- package/dist/tools/suggest-google-business-review-reply.js +5 -4
- package/dist/tools/test-webhook.js +7 -1
- package/dist/tools/trigger-platform-helper.js +5 -1
- package/dist/tools/update-oauth-client.js +8 -1
- package/dist/tools/update-post-release-id.js +5 -1
- package/dist/tools/update-post-status.d.ts +2 -2
- package/dist/tools/update-post-status.js +7 -1
- package/dist/tools/update-post.js +10 -4
- package/dist/tools/update-webhook.js +7 -1
- package/dist/tools/upload-media-from-url.js +7 -9
- package/dist/tools/upload-media.js +6 -2
- package/dist/tools/whoami.js +18 -17
- package/package.json +1 -1
- package/src/index.ts +50 -49
- package/src/lib/api-client.ts +1 -1
- package/src/lib/format.ts +132 -0
- package/src/tools/audit-google-business-profile.ts +18 -12
- package/src/tools/create-oauth-client.ts +8 -2
- package/src/tools/create-post.ts +20 -28
- package/src/tools/create-posts-batch.ts +23 -18
- package/src/tools/create-signed-upload.ts +11 -8
- package/src/tools/create-webhook.ts +7 -3
- package/src/tools/delete-google-business-review-reply.ts +4 -1
- package/src/tools/delete-oauth-client.ts +4 -1
- package/src/tools/delete-post-group.ts +5 -1
- package/src/tools/delete-post.ts +4 -1
- package/src/tools/delete-webhook.ts +4 -2
- package/src/tools/disconnect-account.ts +7 -5
- package/src/tools/find-slot.ts +13 -5
- package/src/tools/generate-image.ts +20 -20
- package/src/tools/generate-video.ts +11 -9
- package/src/tools/get-account-analytics.ts +70 -49
- package/src/tools/get-brand-profile.ts +34 -38
- package/src/tools/get-brand.ts +14 -14
- package/src/tools/get-connect-link.ts +29 -7
- package/src/tools/get-google-business-review-link.ts +6 -6
- package/src/tools/get-platform-schema.ts +29 -16
- package/src/tools/get-post-analytics.ts +58 -51
- package/src/tools/get-post-missing.ts +5 -2
- package/src/tools/get-post.ts +16 -13
- package/src/tools/get-video-job.ts +31 -11
- package/src/tools/get-video-options.ts +27 -15
- package/src/tools/get-x-posting-quota.ts +12 -9
- package/src/tools/list-accounts.ts +15 -6
- package/src/tools/list-activity.ts +16 -20
- package/src/tools/list-brand-accounts.ts +14 -6
- package/src/tools/list-brands.ts +16 -13
- package/src/tools/list-google-business-reviews.ts +16 -12
- package/src/tools/list-oauth-clients.ts +13 -4
- package/src/tools/list-platforms.ts +15 -5
- package/src/tools/list-posts.ts +15 -9
- package/src/tools/list-webhooks.ts +16 -12
- package/src/tools/reply-google-business-review.ts +4 -1
- package/src/tools/run-video-function.ts +4 -4
- package/src/tools/suggest-google-business-review-reply.ts +5 -4
- package/src/tools/test-webhook.ts +7 -1
- package/src/tools/trigger-platform-helper.ts +5 -1
- package/src/tools/update-oauth-client.ts +9 -2
- package/src/tools/update-post-release-id.ts +5 -2
- package/src/tools/update-post-status.ts +7 -1
- package/src/tools/update-post.ts +10 -5
- package/src/tools/update-webhook.ts +7 -2
- package/src/tools/upload-media-from-url.ts +7 -9
- package/src/tools/upload-media.ts +6 -2
- package/src/tools/whoami.ts +21 -23
package/src/tools/get-brand.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
import { code, formatDateTime, mdKeyValue, mdTitle } from '../lib/format.js';
|
|
3
4
|
|
|
4
5
|
export const getBrandTool = {
|
|
5
6
|
name: 'get_brand',
|
|
@@ -16,19 +17,18 @@ export const getBrandTool = {
|
|
|
16
17
|
const result = await client.getBrand(input.brand_id);
|
|
17
18
|
const brand = result.brand as Record<string, any>;
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
`Brand: ${brand.name}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return lines.join('\n');
|
|
20
|
+
return [
|
|
21
|
+
mdTitle(`Brand: ${brand.name}`),
|
|
22
|
+
mdKeyValue([
|
|
23
|
+
['Brand ID', code(brand.id)],
|
|
24
|
+
['Source', brand.source],
|
|
25
|
+
['Workspace', brand.workspace_id ? code(brand.workspace_id) : 'n/a'],
|
|
26
|
+
['Accounts assigned', brand.account_count ?? 0],
|
|
27
|
+
['Workspace client ID', brand.workspace_client_id ? code(brand.workspace_client_id) : undefined],
|
|
28
|
+
['Legacy brand group ID', brand.legacy_brand_group_id ? code(brand.legacy_brand_group_id) : undefined],
|
|
29
|
+
['Created', formatDateTime(brand.created_at)],
|
|
30
|
+
['Updated', formatDateTime(brand.updated_at)],
|
|
31
|
+
]),
|
|
32
|
+
].join('\n\n');
|
|
33
33
|
},
|
|
34
34
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { ConnectOption, PosterlyClient } from '../lib/api-client.js';
|
|
3
3
|
import { CONNECT_INPUTS, PLANNED_PLATFORM_IDS } from '../generated/platform-manifest.js';
|
|
4
|
+
import { code, mdJson, mdKeyValue, mdSection, mdTable, mdTitle, statusLabel } from '../lib/format.js';
|
|
4
5
|
|
|
5
6
|
export const getConnectLinkTool = {
|
|
6
7
|
name: 'get_connect_link',
|
|
@@ -31,8 +32,21 @@ export const getConnectLinkTool = {
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
const options = result.connect_options || [];
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
return [
|
|
36
|
+
mdTitle(`Posterly connection options (${options.length})`),
|
|
37
|
+
mdTable(
|
|
38
|
+
['Provider', 'Target', 'Status', 'Method', 'Connected', 'Readiness'],
|
|
39
|
+
options.map((option) => [
|
|
40
|
+
option.label,
|
|
41
|
+
code(option.platform),
|
|
42
|
+
statusLabel(option.status),
|
|
43
|
+
option.method,
|
|
44
|
+
option.connected_count ?? option.connected_accounts?.length ?? 0,
|
|
45
|
+
option.missing_env?.length ? 'missing config' : 'configured',
|
|
46
|
+
]),
|
|
47
|
+
),
|
|
48
|
+
'**Tip:** Call this tool with a specific `platform` to get the direct dashboard handoff URL.',
|
|
49
|
+
].join('\n\n');
|
|
36
50
|
},
|
|
37
51
|
};
|
|
38
52
|
|
|
@@ -45,12 +59,20 @@ function formatConnectOption(option: ConnectOption, includeRaw: boolean): string
|
|
|
45
59
|
? `; credential fields: ${option.credential_fields.map((field: any) => field.key).join(', ')}`
|
|
46
60
|
: '';
|
|
47
61
|
const scopes = option.scopes?.length ? `; scopes: ${option.scopes.join(', ')}` : '';
|
|
48
|
-
const raw = includeRaw ?
|
|
62
|
+
const raw = includeRaw ? mdJson('Raw connect option', option) : '';
|
|
49
63
|
|
|
50
64
|
return [
|
|
51
|
-
`${option.label} (
|
|
52
|
-
|
|
53
|
-
|
|
65
|
+
mdTitle(`${option.label} connection`, code(option.platform)),
|
|
66
|
+
mdKeyValue([
|
|
67
|
+
['Status', statusLabel(option.status)],
|
|
68
|
+
['Method', option.method],
|
|
69
|
+
['Readiness', missing],
|
|
70
|
+
['Connected accounts', accounts],
|
|
71
|
+
['Connection URL', option.connection_url || 'not available'],
|
|
72
|
+
['Credential fields', fields.replace(/^; credential fields: /, '') || undefined],
|
|
73
|
+
['Scopes', scopes.replace(/^; scopes: /, '') || undefined],
|
|
74
|
+
]),
|
|
75
|
+
option.notes?.length ? mdSection('Notes', option.notes.map((note) => `- ${note}`).join('\n')) : '',
|
|
54
76
|
raw,
|
|
55
|
-
].join('\n');
|
|
77
|
+
].filter(Boolean).join('\n\n');
|
|
56
78
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
import { code, mdSuccess } from '../lib/format.js';
|
|
3
4
|
|
|
4
5
|
export const getGoogleBusinessReviewLinkTool = {
|
|
5
6
|
name: 'get_google_business_review_link',
|
|
@@ -20,11 +21,10 @@ export const getGoogleBusinessReviewLinkTool = {
|
|
|
20
21
|
},
|
|
21
22
|
) {
|
|
22
23
|
const result = await client.getGoogleBusinessReviewLink(input);
|
|
23
|
-
return [
|
|
24
|
-
|
|
25
|
-
result.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
].join('\n');
|
|
24
|
+
return mdSuccess(`Review link for ${result.businessName}`, [
|
|
25
|
+
['Review link', result.reviewLink],
|
|
26
|
+
['Place ID', code(result.placeId)],
|
|
27
|
+
['Account ID', code(result.account_id)],
|
|
28
|
+
]);
|
|
29
29
|
},
|
|
30
30
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
3
|
import { ALL_PLATFORM_INPUTS, SUPPORTED_PLATFORM_IDS } from '../generated/platform-manifest.js';
|
|
4
|
+
import { code, mdJson, mdKeyValue, mdSection, mdTable, mdTitle, statusLabel } from '../lib/format.js';
|
|
4
5
|
|
|
5
6
|
export const getPlatformSchemaTool = {
|
|
6
7
|
name: 'get_platform_schema',
|
|
@@ -24,29 +25,41 @@ export const getPlatformSchemaTool = {
|
|
|
24
25
|
) {
|
|
25
26
|
const result = await client.getPlatformSchema(input);
|
|
26
27
|
const schema = result.schema || result.platform || result.platforms?.[0];
|
|
27
|
-
if (!schema) return
|
|
28
|
+
if (!schema) return mdJson('Platform schema response', result);
|
|
28
29
|
|
|
29
30
|
const fields = schema.settings_schema?.fields || [];
|
|
30
31
|
const helpers = schema.helper_tools || [];
|
|
31
|
-
const accountLine = result.account
|
|
32
|
-
? `Account: ${(result.account.username as string) || result.account.id} (${result.account.platform})\n`
|
|
33
|
-
: '';
|
|
34
32
|
|
|
35
33
|
return [
|
|
36
|
-
`${schema.label} (
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
34
|
+
mdTitle(`${schema.label} schema`, code(schema.id)),
|
|
35
|
+
mdKeyValue([
|
|
36
|
+
['Account', result.account ? `${(result.account.username as string) || result.account.id} (${result.account.platform})` : undefined],
|
|
37
|
+
['Status', statusLabel(schema.status)],
|
|
38
|
+
['Post types', schema.post_types.join(', ') || 'n/a'],
|
|
39
|
+
['Content limit', schema.content_limit ?? 'n/a'],
|
|
40
|
+
['Analytics', schema.analytics_supported],
|
|
41
|
+
]),
|
|
43
42
|
fields.length
|
|
44
|
-
?
|
|
45
|
-
|
|
43
|
+
? mdSection('Settings', mdTable(
|
|
44
|
+
['Field', 'Required', 'Description'],
|
|
45
|
+
fields.map((field: any) => [
|
|
46
|
+
code(field.key),
|
|
47
|
+
Boolean(field.required),
|
|
48
|
+
field.description || field.label || 'n/a',
|
|
49
|
+
]),
|
|
50
|
+
))
|
|
51
|
+
: mdSection('Settings', 'None'),
|
|
46
52
|
helpers.length
|
|
47
|
-
?
|
|
48
|
-
|
|
49
|
-
|
|
53
|
+
? mdSection('Helpers', mdTable(
|
|
54
|
+
['Helper', 'Description'],
|
|
55
|
+
helpers.map((helper: any) => [
|
|
56
|
+
code(helper.name),
|
|
57
|
+
helper.description || 'n/a',
|
|
58
|
+
]),
|
|
59
|
+
))
|
|
60
|
+
: mdSection('Helpers', 'None'),
|
|
61
|
+
mdJson('Media rules', schema.media),
|
|
62
|
+
mdJson('Example settings', schema.settings_schema?.example || {}),
|
|
50
63
|
].filter(Boolean).join('\n');
|
|
51
64
|
},
|
|
52
65
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
import { code, compactText, formatDateTime, formatNumber, mdEmpty, mdSection, mdTable, mdTitle } from '../lib/format.js';
|
|
3
4
|
|
|
4
5
|
export const getPostAnalyticsTool = {
|
|
5
6
|
name: 'get_post_analytics',
|
|
@@ -40,59 +41,65 @@ export const getPostAnalyticsTool = {
|
|
|
40
41
|
const { account, range, posts, total } = result;
|
|
41
42
|
|
|
42
43
|
if (posts.length === 0) {
|
|
43
|
-
return `No analytics found for @${account.username} (${account.platform}) between ${range.from} and ${range.to}
|
|
44
|
+
return mdEmpty('post analytics', `No post analytics were found for @${account.username} (${account.platform}) between ${range.from} and ${range.to}.`);
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
const totals = posts.reduce(
|
|
48
|
+
(acc, post) => ({
|
|
49
|
+
likes: acc.likes + post.likes,
|
|
50
|
+
comments: acc.comments + post.comments,
|
|
51
|
+
reach: acc.reach + post.reach,
|
|
52
|
+
impressions: acc.impressions + post.impressions,
|
|
53
|
+
shares: acc.shares + post.shares,
|
|
54
|
+
saves: acc.saves + post.saved,
|
|
55
|
+
}),
|
|
56
|
+
{ likes: 0, comments: 0, reach: 0, impressions: 0, shares: 0, saves: 0 },
|
|
57
|
+
);
|
|
51
58
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
metrics.push(`${Math.round(p.total_watch_time_ms / 60000).toLocaleString()} watch minutes`);
|
|
72
|
-
}
|
|
73
|
-
if (account.platform === 'youtube' && p.avg_watch_time_ms) {
|
|
74
|
-
metrics.push(`${Math.round(p.avg_watch_time_ms / 1000)}s avg view`);
|
|
75
|
-
}
|
|
76
|
-
if (p.url_link_clicks) {
|
|
77
|
-
metrics.push(
|
|
78
|
-
account.platform === 'pinterest'
|
|
79
|
-
? `${p.url_link_clicks.toLocaleString()} outbound clicks`
|
|
80
|
-
: `${p.url_link_clicks.toLocaleString()} link clicks`
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
if (p.user_profile_clicks) {
|
|
84
|
-
metrics.push(
|
|
85
|
-
account.platform === 'pinterest'
|
|
86
|
-
? `${p.user_profile_clicks.toLocaleString()} pin clicks`
|
|
87
|
-
: `${p.user_profile_clicks.toLocaleString()} profile clicks`
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
lines.push(`• [${postedAt}] ${caption}`);
|
|
92
|
-
lines.push(` ${metrics.join(' • ')}`);
|
|
93
|
-
if (p.permalink) lines.push(` ${p.permalink}`);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return lines.join('\n');
|
|
59
|
+
return [
|
|
60
|
+
mdTitle(`📈 Post analytics for @${account.username}`, `${account.platform} · ${range.from} → ${range.to} · showing ${posts.length} of ${total}`),
|
|
61
|
+
mdSection('Returned totals', mdTable(
|
|
62
|
+
['Likes', 'Comments', 'Reach', 'Impressions', 'Shares', 'Saves'],
|
|
63
|
+
[[totals.likes, totals.comments, totals.reach, totals.impressions, totals.shares, totals.saves]],
|
|
64
|
+
)),
|
|
65
|
+
mdSection('Posts', mdTable(
|
|
66
|
+
['Posted', 'Post', 'Caption', 'Reach', 'Likes', 'Comments', 'Extras'],
|
|
67
|
+
posts.map((post) => [
|
|
68
|
+
formatDateTime(post.posted_at),
|
|
69
|
+
post.id ? code(post.id) : code(post.platform_media_id),
|
|
70
|
+
compactText(post.caption_snippet, 70) || '(no caption)',
|
|
71
|
+
formatNumber(post.reach),
|
|
72
|
+
formatNumber(post.likes),
|
|
73
|
+
formatNumber(post.comments),
|
|
74
|
+
buildExtras(account.platform, post),
|
|
75
|
+
]),
|
|
76
|
+
)),
|
|
77
|
+
].join('\n\n');
|
|
97
78
|
},
|
|
98
79
|
};
|
|
80
|
+
|
|
81
|
+
function buildExtras(platform: string, post: any): string {
|
|
82
|
+
const metrics: string[] = [];
|
|
83
|
+
if (post.impressions) metrics.push(`${formatNumber(post.impressions)} impressions`);
|
|
84
|
+
if (post.saved) metrics.push(`${formatNumber(post.saved)} saved`);
|
|
85
|
+
if (post.shares) metrics.push(`${formatNumber(post.shares)} shares`);
|
|
86
|
+
if (post.plays) metrics.push(`${formatNumber(post.plays)} plays`);
|
|
87
|
+
if (platform === 'youtube' && post.total_watch_time_ms) {
|
|
88
|
+
metrics.push(`${formatNumber(Math.round(post.total_watch_time_ms / 60000))} watch minutes`);
|
|
89
|
+
}
|
|
90
|
+
if (platform === 'youtube' && post.avg_watch_time_ms) {
|
|
91
|
+
metrics.push(`${formatNumber(Math.round(post.avg_watch_time_ms / 1000))}s avg view`);
|
|
92
|
+
}
|
|
93
|
+
if (post.url_link_clicks) {
|
|
94
|
+
metrics.push(platform === 'pinterest'
|
|
95
|
+
? `${formatNumber(post.url_link_clicks)} outbound clicks`
|
|
96
|
+
: `${formatNumber(post.url_link_clicks)} link clicks`);
|
|
97
|
+
}
|
|
98
|
+
if (post.user_profile_clicks) {
|
|
99
|
+
metrics.push(platform === 'pinterest'
|
|
100
|
+
? `${formatNumber(post.user_profile_clicks)} pin clicks`
|
|
101
|
+
: `${formatNumber(post.user_profile_clicks)} profile clicks`);
|
|
102
|
+
}
|
|
103
|
+
if (post.permalink) metrics.push(post.permalink);
|
|
104
|
+
return metrics.join(' · ') || 'n/a';
|
|
105
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
import { code, mdJson, mdTitle } from '../lib/format.js';
|
|
3
4
|
|
|
4
5
|
export const getPostMissingTool = {
|
|
5
6
|
name: 'get_post_missing',
|
|
@@ -11,7 +12,9 @@ export const getPostMissingTool = {
|
|
|
11
12
|
|
|
12
13
|
async execute(client: PosterlyClient, input: { post_id: number }) {
|
|
13
14
|
const result = await client.getPostMissing(input.post_id);
|
|
14
|
-
return
|
|
15
|
+
return [
|
|
16
|
+
mdTitle(`Post readiness for ${code(input.post_id)}`),
|
|
17
|
+
mdJson('Missing fields response', result),
|
|
18
|
+
].join('\n\n');
|
|
15
19
|
},
|
|
16
20
|
};
|
|
17
|
-
|
package/src/tools/get-post.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
import { code, formatDateTime, mdKeyValue, mdQuote, mdSection, mdTitle, statusLabel } from '../lib/format.js';
|
|
3
4
|
|
|
4
5
|
export const getPostTool = {
|
|
5
6
|
name: 'get_post',
|
|
@@ -16,18 +17,20 @@ export const getPostTool = {
|
|
|
16
17
|
const result = await client.getPost(input.post_id);
|
|
17
18
|
const p = result.post as Record<string, any>;
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
`Post
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
20
|
+
return [
|
|
21
|
+
mdTitle(`Post ${code(p.id)}`),
|
|
22
|
+
mdKeyValue([
|
|
23
|
+
['Status', statusLabel(p.status)],
|
|
24
|
+
['Type', p.post_type || 'unknown'],
|
|
25
|
+
['Scheduled', formatDateTime(p.scheduled_at)],
|
|
26
|
+
['Published URL', p.platform_post_url],
|
|
27
|
+
['Media', p.media_url],
|
|
28
|
+
['Media count', p.media_urls?.length],
|
|
29
|
+
]),
|
|
30
|
+
mdSection('Caption', p.content ? mdQuote(p.content) : '_(empty)_'),
|
|
31
|
+
p.media_urls?.length
|
|
32
|
+
? mdSection('Media URLs', p.media_urls.map((url: string, index: number) => `${index + 1}. ${url}`).join('\n'))
|
|
33
|
+
: '',
|
|
34
|
+
].filter(Boolean).join('\n\n');
|
|
32
35
|
},
|
|
33
36
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { PosterlyClient, VideoJob } from '../lib/api-client.js';
|
|
3
|
+
import { code, compactText, formatDateTime, mdJson, mdKeyValue, mdSection, mdTable, mdTitle, statusLabel } from '../lib/format.js';
|
|
3
4
|
|
|
4
5
|
export const getVideoJobTool = {
|
|
5
6
|
name: 'get_video_job',
|
|
@@ -17,20 +18,39 @@ export const getVideoJobTool = {
|
|
|
17
18
|
|
|
18
19
|
const jobs = result.jobs || [];
|
|
19
20
|
return [
|
|
20
|
-
`Video jobs (${jobs.length})
|
|
21
|
-
|
|
21
|
+
mdTitle(`Video jobs (${jobs.length})`),
|
|
22
|
+
mdTable(
|
|
23
|
+
['Job ID', 'Status', 'Prompt', 'Model', 'Created', 'Cost'],
|
|
24
|
+
jobs.map((job) => [
|
|
25
|
+
code(job.id),
|
|
26
|
+
statusLabel(job.status),
|
|
27
|
+
compactText(job.prompt, 70),
|
|
28
|
+
job.model,
|
|
29
|
+
formatDateTime(job.created_at),
|
|
30
|
+
job.credit_cost,
|
|
31
|
+
]),
|
|
32
|
+
),
|
|
22
33
|
].filter(Boolean).join('\n');
|
|
23
34
|
},
|
|
24
35
|
};
|
|
25
36
|
|
|
26
37
|
function formatJob(job: VideoJob, includeRaw: boolean): string {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
return [
|
|
39
|
+
mdTitle(`Video job ${code(job.id)}`),
|
|
40
|
+
mdKeyValue([
|
|
41
|
+
['Status', statusLabel(job.status)],
|
|
42
|
+
['Model', job.model],
|
|
43
|
+
['Duration', `${job.duration_seconds}s`],
|
|
44
|
+
['Aspect ratio', job.aspect_ratio],
|
|
45
|
+
['Resolution', job.resolution || 'n/a'],
|
|
46
|
+
['Credit cost', job.credit_cost],
|
|
47
|
+
['Created', formatDateTime(job.created_at)],
|
|
48
|
+
['Started', formatDateTime(job.started_at)],
|
|
49
|
+
['Completed', formatDateTime(job.completed_at)],
|
|
50
|
+
['Video URL', job.video_url || undefined],
|
|
51
|
+
['Error', job.error_message || undefined],
|
|
52
|
+
]),
|
|
53
|
+
mdSection('Prompt', job.prompt),
|
|
54
|
+
includeRaw ? mdJson('Raw job', job) : '',
|
|
55
|
+
].filter(Boolean).join('\n\n');
|
|
36
56
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
import { code, mdJson, mdKeyValue, mdSection, mdTable, mdTitle } from '../lib/format.js';
|
|
3
4
|
|
|
4
5
|
export const getVideoOptionsTool = {
|
|
5
6
|
name: 'get_video_options',
|
|
@@ -11,20 +12,31 @@ export const getVideoOptionsTool = {
|
|
|
11
12
|
const options = await client.getVideoOptions();
|
|
12
13
|
const models = Array.isArray(options.models) ? options.models : [];
|
|
13
14
|
const inputModes = Array.isArray(options.input_modes) ? options.input_modes : [];
|
|
14
|
-
|
|
15
|
-
'Video generation options',
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
15
|
+
return [
|
|
16
|
+
mdTitle('Video generation options'),
|
|
17
|
+
mdKeyValue([
|
|
18
|
+
['Provider', options.provider || 'unknown'],
|
|
19
|
+
['Public generation status', options.public_generation_status || 'unknown'],
|
|
20
|
+
['Durations', `${(options.durations_seconds || []).join(', ')} seconds`],
|
|
21
|
+
['Resolutions', (options.resolutions || []).join(', ')],
|
|
22
|
+
['Aspect ratios', (options.aspect_ratios || []).join(', ')],
|
|
23
|
+
]),
|
|
24
|
+
mdSection('Models', mdTable(
|
|
25
|
+
['Model', 'Label', 'Credit cost'],
|
|
26
|
+
models.map((model: any) => [
|
|
27
|
+
code(model.id),
|
|
28
|
+
model.label || model.name || 'n/a',
|
|
29
|
+
model.credit_cost ?? model.cost ?? 'n/a',
|
|
30
|
+
]),
|
|
31
|
+
)),
|
|
32
|
+
mdSection('Input modes', mdTable(
|
|
33
|
+
['Mode', 'Label'],
|
|
34
|
+
inputModes.map((mode: any) => [
|
|
35
|
+
code(mode.id),
|
|
36
|
+
mode.label || mode.name || 'n/a',
|
|
37
|
+
]),
|
|
38
|
+
)),
|
|
39
|
+
mdJson('Raw options', options),
|
|
40
|
+
].filter(Boolean).join('\n\n');
|
|
29
41
|
},
|
|
30
42
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
import { code, mdKeyValue, mdTitle, statusLabel } from '../lib/format.js';
|
|
3
4
|
|
|
4
5
|
export const getXPostingQuotaTool = {
|
|
5
6
|
name: 'get_x_posting_quota',
|
|
@@ -12,14 +13,16 @@ export const getXPostingQuotaTool = {
|
|
|
12
13
|
async execute(client: PosterlyClient, input: { workspace_id?: string }) {
|
|
13
14
|
const quota = await client.getXPostingQuota(input);
|
|
14
15
|
return [
|
|
15
|
-
'X posting quota',
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
mdTitle('X posting quota'),
|
|
17
|
+
mdKeyValue([
|
|
18
|
+
['Workspace', quota.workspace_id ? code(quota.workspace_id) : 'default'],
|
|
19
|
+
['Tier', quota.tier || 'unknown'],
|
|
20
|
+
['Total posts', quota.total_posts],
|
|
21
|
+
['Used posts', quota.used_posts],
|
|
22
|
+
['Remaining posts', quota.remaining_posts],
|
|
23
|
+
['URL posting', statusLabel(quota.urls_blocked ? 'blocked' : 'available')],
|
|
24
|
+
['Period', `${quota.current_period_start} → ${quota.current_period_end}`],
|
|
25
|
+
]),
|
|
26
|
+
].join('\n\n');
|
|
24
27
|
},
|
|
25
28
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
import { code, mdEmpty, mdTable, mdTitle } from '../lib/format.js';
|
|
3
4
|
|
|
4
5
|
export const listAccountsTool = {
|
|
5
6
|
name: 'list_accounts',
|
|
@@ -17,13 +18,21 @@ export const listAccountsTool = {
|
|
|
17
18
|
|
|
18
19
|
if (accounts.length === 0) {
|
|
19
20
|
return input.workspace_id
|
|
20
|
-
? '
|
|
21
|
-
: '
|
|
21
|
+
? mdEmpty('connected accounts', 'This workspace does not have any social accounts connected yet.')
|
|
22
|
+
: mdEmpty('connected accounts', 'Posterly does not see any connected social accounts yet.', 'Connect accounts in the Posterly dashboard, then run this again.');
|
|
22
23
|
}
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
(
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
return [
|
|
26
|
+
mdTitle(`Connected accounts (${accounts.length})`),
|
|
27
|
+
mdTable(
|
|
28
|
+
['Platform', 'Account', 'Account ID', 'Workspace'],
|
|
29
|
+
accounts.map((account) => [
|
|
30
|
+
account.platform,
|
|
31
|
+
`@${account.username}`,
|
|
32
|
+
code(account.id),
|
|
33
|
+
account.workspace_id ? code(account.workspace_id) : 'default',
|
|
34
|
+
]),
|
|
35
|
+
),
|
|
36
|
+
].join('\n\n');
|
|
28
37
|
},
|
|
29
38
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
import { compactText, formatDateTime, mdEmpty, mdTable, mdTitle } from '../lib/format.js';
|
|
3
4
|
|
|
4
5
|
export const listActivityTool = {
|
|
5
6
|
name: 'list_activity',
|
|
@@ -25,27 +26,22 @@ export const listActivityTool = {
|
|
|
25
26
|
) {
|
|
26
27
|
const result = await client.listActivity(input);
|
|
27
28
|
if (result.items.length === 0) {
|
|
28
|
-
return 'No activity
|
|
29
|
+
return mdEmpty('activity', 'No activity matched those filters.');
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
`Activity (${result.items.length} of ${result.total})
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return lines.join('\n');
|
|
32
|
+
return [
|
|
33
|
+
mdTitle(`Activity (${result.items.length} of ${result.total})`),
|
|
34
|
+
mdTable(
|
|
35
|
+
['When', 'Source', 'Post', 'Platform', 'Event', 'Detail'],
|
|
36
|
+
result.items.map((item) => [
|
|
37
|
+
formatDateTime(item.created_at),
|
|
38
|
+
item.type,
|
|
39
|
+
item.post_id ?? '?',
|
|
40
|
+
item.platform || 'n/a',
|
|
41
|
+
item.type === 'publish' ? item.outcome || 'publish' : item.action || 'activity',
|
|
42
|
+
compactText(item.error_message || item.description, 120) || 'n/a',
|
|
43
|
+
]),
|
|
44
|
+
),
|
|
45
|
+
].join('\n\n');
|
|
49
46
|
},
|
|
50
47
|
};
|
|
51
|
-
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
import { code, mdEmpty, mdTable, mdTitle } from '../lib/format.js';
|
|
3
4
|
|
|
4
5
|
export const listBrandAccountsTool = {
|
|
5
6
|
name: 'list_brand_accounts',
|
|
@@ -16,13 +17,20 @@ export const listBrandAccountsTool = {
|
|
|
16
17
|
const accounts = await client.listBrandAccounts(input.brand_id);
|
|
17
18
|
|
|
18
19
|
if (accounts.length === 0) {
|
|
19
|
-
return 'No social accounts are currently assigned to this brand.';
|
|
20
|
+
return mdEmpty('brand accounts', 'No social accounts are currently assigned to this brand.');
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
return [
|
|
24
|
+
mdTitle(`Brand accounts (${accounts.length})`),
|
|
25
|
+
mdTable(
|
|
26
|
+
['Platform', 'Account', 'Account ID', 'Workspace'],
|
|
27
|
+
accounts.map((account) => [
|
|
28
|
+
account.platform,
|
|
29
|
+
`@${account.username}`,
|
|
30
|
+
code(account.id),
|
|
31
|
+
account.workspace_id ? code(account.workspace_id) : 'default',
|
|
32
|
+
]),
|
|
33
|
+
),
|
|
34
|
+
].join('\n\n');
|
|
27
35
|
},
|
|
28
36
|
};
|