@jclvsh/dropspace 2.42.0 → 2.43.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 +5 -1
- package/dist/commands/audience.js +92 -0
- package/dist/server.js +2 -0
- package/dist/tool-policy.js +5 -0
- package/dist/tools/comments.js +1 -1
- package/dist/tools/trial-reels.d.ts +3 -0
- package/dist/tools/trial-reels.js +77 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -377,6 +377,10 @@ Reddit engagement (drafted comments in other communities) is paused: its tools a
|
|
|
377
377
|
| `get_audience_demographics` | Age, gender, country, and city of your Instagram followers and engaged audience (local package only, not the hosted endpoint) |
|
|
378
378
|
| `get_reels_read` | Each Instagram account's latest reels read (local package only, not the hosted endpoint) |
|
|
379
379
|
| `generate_reels_read` | Claude compares your top, middle, and bottom reels of the last 90 days; pro and premium, one a day per account (local package only, not the hosted endpoint) |
|
|
380
|
+
| `list_trial_reels` | Trial reel programs: each Instagram account's program, posting hours, and reshared reels with their 1/3/7-day numbers; pro and premium (local package only) |
|
|
381
|
+
| `update_trial_reel_program` | Turn an account's trial reel program on or off, or change reels per day, auto-approve, skip terms, timezone (send scope to turn on; local package only) |
|
|
382
|
+
| `scan_trial_reels` | Scan an account's reels again and queue the strong ones (local package only) |
|
|
383
|
+
| `update_trial_reel` | Approve, hold, re-caption, or remove a waiting reel, or approve all (send scope to approve; local package only) |
|
|
380
384
|
|
|
381
385
|
#### `get_audience` Parameters
|
|
382
386
|
|
|
@@ -385,7 +389,7 @@ Reddit engagement (drafted comments in other communities) is paused: its tools a
|
|
|
385
389
|
| `window_days` | number | No | Growth window in days (1-365, default 30) |
|
|
386
390
|
| `include_instagram_insights` | boolean | No | Add Instagram growth analytics to each Instagram entry (default false) |
|
|
387
391
|
|
|
388
|
-
CLI: `dropspace audience [-w, --window-days <n>] [--instagram-insights]`, `dropspace trial-reels`, `dropspace best-hours [--timezone <zone>]`, `dropspace demographics [--timeframe <this_week|this_month|last_90_days>]`,
|
|
392
|
+
CLI: `dropspace audience [-w, --window-days <n>] [--instagram-insights]`, `dropspace trial-reels`, `dropspace best-hours [--timezone <zone>]`, `dropspace demographics [--timeframe <this_week|this_month|last_90_days>]`, `dropspace reels-read [--generate] [--connection-id <id>]`, and `dropspace trial-reel-program list|set|scan|approve|approve-all|remove`.
|
|
389
393
|
|
|
390
394
|
With `include_instagram_insights`, each Instagram entry carries `instagram_insights`: follows, unfollows, net, and reach split into followers and non-followers per Pacific-time day, an estimated followers-over-time series rebuilt back from the current count, weekly growth velocity, the share of reach from non-followers, and contact-button taps. Instagram revises the last 7 days (`settled: false`). Each call reads up to 31 days, newest first, so a 90-day window fills over a few calls (`days_pending`). Instagram reports none of this for accounts under 100 followers (`available: false`).
|
|
391
395
|
|
|
@@ -108,4 +108,96 @@ export function registerAudienceCommands(program, client) {
|
|
|
108
108
|
}
|
|
109
109
|
});
|
|
110
110
|
}
|
|
111
|
+
const trial = program
|
|
112
|
+
.command("trial-reel-program")
|
|
113
|
+
.description("reshare your strongest instagram reels as trial reels (pro and premium)");
|
|
114
|
+
trial
|
|
115
|
+
.command("list")
|
|
116
|
+
.description("each instagram account with its trial reel program, posting hours, and reels")
|
|
117
|
+
.action(async () => {
|
|
118
|
+
try {
|
|
119
|
+
formatOutput(await client.get("/trial-reels"), getFormat(program.opts()));
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
handleError(error);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
trial
|
|
126
|
+
.command("set <connectionId>")
|
|
127
|
+
.description("change a program; --on needs the send scope and scans the account's reels the first time")
|
|
128
|
+
.option("--on", "turn the program on")
|
|
129
|
+
.option("--off", "turn the program off")
|
|
130
|
+
.option("--per-day <n>", "trial reels a day, 1-3")
|
|
131
|
+
.option("--auto-approve <bool>", "post queued reels without approving each one (true or false)")
|
|
132
|
+
.option("--skip <terms>", "comma-separated: never queue a reel whose caption contains one")
|
|
133
|
+
.option("--timezone <tz>", "IANA timezone for posting hours")
|
|
134
|
+
.action(async (connectionId, options) => {
|
|
135
|
+
try {
|
|
136
|
+
const body = {
|
|
137
|
+
...(options.on ? { enabled: true } : options.off ? { enabled: false } : {}),
|
|
138
|
+
...(options.perDay ? { reels_per_day: Number(options.perDay) } : {}),
|
|
139
|
+
...(options.autoApprove !== undefined
|
|
140
|
+
? { auto_approve: ["true", "yes", "on", "1"].includes(options.autoApprove.toLowerCase()) }
|
|
141
|
+
: {}),
|
|
142
|
+
...(options.skip !== undefined
|
|
143
|
+
? {
|
|
144
|
+
skip_caption_terms: options.skip
|
|
145
|
+
.split(",")
|
|
146
|
+
.map((term) => term.trim())
|
|
147
|
+
.filter(Boolean),
|
|
148
|
+
}
|
|
149
|
+
: {}),
|
|
150
|
+
...(options.timezone ? { timezone: options.timezone } : {}),
|
|
151
|
+
};
|
|
152
|
+
formatOutput(await client.put(`/trial-reels/programs/${connectionId}`, body), getFormat(program.opts()));
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
handleError(error);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
trial
|
|
159
|
+
.command("scan <connectionId>")
|
|
160
|
+
.description("scan the account's reels again and queue the strong ones")
|
|
161
|
+
.action(async (connectionId) => {
|
|
162
|
+
try {
|
|
163
|
+
formatOutput(await client.post(`/trial-reels/programs/${connectionId}/scan`), getFormat(program.opts()));
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
handleError(error);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
trial
|
|
170
|
+
.command("approve <itemId>")
|
|
171
|
+
.description("approve a waiting reel so it posts at the next posting hour (send scope)")
|
|
172
|
+
.action(async (itemId) => {
|
|
173
|
+
try {
|
|
174
|
+
formatOutput(await client.patch(`/trial-reels/items/${itemId}`, { approved: true }), getFormat(program.opts()));
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
handleError(error);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
trial
|
|
181
|
+
.command("approve-all <connectionId>")
|
|
182
|
+
.description("approve every waiting reel with a caption (send scope)")
|
|
183
|
+
.action(async (connectionId) => {
|
|
184
|
+
try {
|
|
185
|
+
formatOutput(await client.post(`/trial-reels/programs/${connectionId}/approve-all`), getFormat(program.opts()));
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
handleError(error);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
trial
|
|
192
|
+
.command("remove <itemId>")
|
|
193
|
+
.description("remove a waiting reel for good")
|
|
194
|
+
.action(async (itemId) => {
|
|
195
|
+
try {
|
|
196
|
+
await client.delete(`/trial-reels/items/${itemId}`);
|
|
197
|
+
formatOutput({ data: { id: itemId, status: "removed" } }, getFormat(program.opts()));
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
handleError(error);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
111
203
|
}
|
package/dist/server.js
CHANGED
|
@@ -17,6 +17,7 @@ import { registerRedditTools } from "./tools/reddit.js";
|
|
|
17
17
|
import { registerAudienceTools } from "./tools/audience.js";
|
|
18
18
|
import { registerCommentTools } from "./tools/comments.js";
|
|
19
19
|
import { registerAccountTools } from "./tools/account.js";
|
|
20
|
+
import { registerTrialReelTools } from "./tools/trial-reels.js";
|
|
20
21
|
/** Drops tools whose feature is paused before the policy registrar sees them (see PAUSED_TOOLS). */
|
|
21
22
|
function skipPausedTools(registrar) {
|
|
22
23
|
return {
|
|
@@ -46,5 +47,6 @@ export function createDropspaceServer({ client, version, profile }) {
|
|
|
46
47
|
registerAudienceTools(registrar, client);
|
|
47
48
|
registerCommentTools(registrar, client);
|
|
48
49
|
registerAccountTools(registrar, client);
|
|
50
|
+
registerTrialReelTools(registrar, client);
|
|
49
51
|
return server;
|
|
50
52
|
}
|
package/dist/tool-policy.js
CHANGED
|
@@ -128,6 +128,11 @@ const FULL_TOOL_POLICY = {
|
|
|
128
128
|
get_reels_read: localOnly("audience", "read"),
|
|
129
129
|
// spends a Claude call and up to 60 Instagram requests; changes nothing the user posted
|
|
130
130
|
generate_reels_read: localOnly("audience", "write"),
|
|
131
|
+
list_trial_reels: localOnly("audience", "read"),
|
|
132
|
+
// turning a program on or approving reels leads to instagram posts
|
|
133
|
+
update_trial_reel_program: localOnly("audience", "sensitive"),
|
|
134
|
+
scan_trial_reels: localOnly("audience", "write"),
|
|
135
|
+
update_trial_reel: localOnly("audience", "sensitive"),
|
|
131
136
|
get_usage: hosted("usage", "read"),
|
|
132
137
|
get_changelog: hosted("usage", "read"),
|
|
133
138
|
get_dropspace_status: hosted("dropspace", "read"),
|
package/dist/tools/comments.js
CHANGED
|
@@ -76,7 +76,7 @@ export function registerCommentTools(server, client) {
|
|
|
76
76
|
return fail(error);
|
|
77
77
|
}
|
|
78
78
|
});
|
|
79
|
-
server.tool("list_comment_queue", "every comment still waiting for you across your instagram and youtube posts made through dropspace in the last 30 days (
|
|
79
|
+
server.tool("list_comment_queue", "every comment still waiting for you across your instagram and youtube posts made through dropspace in the last 30 days (up to 30 posts, the ones with comments first; newest 50 comments each; posts_in_window says how many posts the window has), newest first, up to 200. waiting: not hidden, not written or answered by your account, and not replied to, hidden, deleted, or dismissed through dropspace. each comment carries its post (platform, post_id, launch_id, launch_name) and claude's read: kind (question, feedback, praise, spam, attack, other; null until sorted), suggested_action (reply, hide, dismiss), and reply_draft for questions and feedback; may_be_answered is true when youtube returned only some replies and none was yours. counts per kind; post_issues lists posts that could not be read. reply with reply_to_comment, delete with delete_comment (launch_id + post_id + comment id); hide or dismiss several with act_on_comments.", {}, async () => {
|
|
80
80
|
try {
|
|
81
81
|
return text(await client.get("/comments/queue"));
|
|
82
82
|
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
function text(result) {
|
|
3
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4
|
+
}
|
|
5
|
+
function fail(error) {
|
|
6
|
+
return {
|
|
7
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
8
|
+
isError: true,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export function registerTrialReelTools(server, client) {
|
|
12
|
+
server.tool("list_trial_reels", "trial reel programs (pro and premium): each connected instagram account with eligible (instagram takes trial reels only from professional accounts with 200+ followers), its program (absent until saved: enabled, auto_approve, reels_per_day 1-3, skip_caption_terms, timezone, last_note), posting_hours (0-23 in the program's timezone: the account's best hours, else 9, 13, 18), and items, newest 100: status queued (waits for approval), posting, posted, won, retired, or failed (failure says why), with reason, caption, the source reel and its views, win_target (half the source's views, capped at 10,000), and checkpoints d1/d3/d7.", {}, async () => {
|
|
13
|
+
try {
|
|
14
|
+
return text(await client.get("/trial-reels"));
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
return fail(error);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
server.tool("update_trial_reel_program", "create or change the trial reel program for one instagram account. turning it on the first time scans the account's reels and queues the strong ones (returned as scan). nothing posts until a reel is approved (update_trial_reel, or auto_approve). approved reels are reshared as instagram trial reels (shown to non-followers only, graduation manual) one per posting hour, never within 2 hours of another dropspace post to that account; each is a launch on the user's plan. enabled or auto_approve true needs the send scope.", {
|
|
21
|
+
connection_id: z.string().uuid().describe("instagram connection_id from list_trial_reels"),
|
|
22
|
+
enabled: z.boolean().optional().describe("turn the program on or off"),
|
|
23
|
+
auto_approve: z.boolean().optional().describe("post queued reels without approving each one"),
|
|
24
|
+
reels_per_day: z.number().int().min(1).max(3).optional().describe("trial reels a day, 1-3"),
|
|
25
|
+
skip_caption_terms: z
|
|
26
|
+
.array(z.string().max(50))
|
|
27
|
+
.max(20)
|
|
28
|
+
.optional()
|
|
29
|
+
.describe("never queue a reel whose caption contains one of these"),
|
|
30
|
+
timezone: z.string().optional().describe("IANA timezone for posting hours, e.g. America/New_York"),
|
|
31
|
+
}, async ({ connection_id, ...settings }) => {
|
|
32
|
+
try {
|
|
33
|
+
return text(await client.put(`/trial-reels/programs/${connection_id}`, settings));
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
return fail(error);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
server.tool("scan_trial_reels", "scan an instagram account's reels again (last 180 days, up to 100) and queue the ones with 1.5x the median views or more that are older than 21 days and were never queued. returns queued, rated, median_views, and note (why nothing was queued). one scan per account every 10 minutes.", { connection_id: z.string().uuid().describe("instagram connection_id with a saved program") }, async ({ connection_id }) => {
|
|
40
|
+
try {
|
|
41
|
+
return text(await client.post(`/trial-reels/programs/${connection_id}/scan`));
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
return fail(error);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
server.tool("update_trial_reel", "change one waiting (queued) trial reel: approved true lets it post at the next posting hour (send scope; needs a caption), false holds it; caption replaces the caption it posts with (up to 2,200 characters) and holds the reel unless approved true is sent with it; remove true takes it out of the queue for good. approve every waiting reel at once with approve_all.", {
|
|
48
|
+
id: z.string().uuid().optional().describe("item id from list_trial_reels (not needed with approve_all)"),
|
|
49
|
+
approved: z.boolean().optional(),
|
|
50
|
+
caption: z.string().max(2200).optional(),
|
|
51
|
+
remove: z.boolean().optional(),
|
|
52
|
+
approve_all: z
|
|
53
|
+
.string()
|
|
54
|
+
.uuid()
|
|
55
|
+
.optional()
|
|
56
|
+
.describe("instead of one item: a connection_id whose waiting reels with captions are all approved"),
|
|
57
|
+
}, async ({ id, approved, caption, remove, approve_all }) => {
|
|
58
|
+
try {
|
|
59
|
+
if (approve_all) {
|
|
60
|
+
return text(await client.post(`/trial-reels/programs/${approve_all}/approve-all`));
|
|
61
|
+
}
|
|
62
|
+
if (!id)
|
|
63
|
+
return fail(new Error("send id, or approve_all with a connection_id"));
|
|
64
|
+
if (remove) {
|
|
65
|
+
await client.delete(`/trial-reels/items/${id}`);
|
|
66
|
+
return text({ data: { id, status: "removed" } });
|
|
67
|
+
}
|
|
68
|
+
return text(await client.patch(`/trial-reels/items/${id}`, {
|
|
69
|
+
...(approved !== undefined ? { approved } : {}),
|
|
70
|
+
...(caption !== undefined ? { caption } : {}),
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
return fail(error);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|