social-autoposter 1.6.79 → 1.6.80
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/mcp/dist/index.js +65 -15
- package/mcp/dist/runtime.js +2 -1
- package/mcp/dist/version.json +2 -2
- package/mcp/manifest.json +1 -1
- package/mcp/package.json +1 -1
- package/package.json +1 -1
package/mcp/dist/index.js
CHANGED
|
@@ -183,17 +183,21 @@ const server = new McpServer({
|
|
|
183
183
|
"autopilot by calling the HOST tool `create_scheduled_task` with: taskId " +
|
|
184
184
|
"'social-autoposter-autopilot'; cronExpression '* * * * *' (continuous, like the pipeline; the " +
|
|
185
185
|
"host runs one at a time and skips overlapping fires, so cycles run back-to-back); and a " +
|
|
186
|
-
"self-contained prompt telling the run to
|
|
187
|
-
"
|
|
188
|
-
"
|
|
189
|
-
"
|
|
190
|
-
"
|
|
191
|
-
"
|
|
192
|
-
"
|
|
193
|
-
"
|
|
194
|
-
"
|
|
195
|
-
"
|
|
196
|
-
"
|
|
186
|
+
"self-contained prompt telling the run to use ONLY two tools — scan_candidates and submit_drafts " +
|
|
187
|
+
"— and to IMPROVISE NOTHING ELSE. Specifically the prompt must say: (1) call scan_candidates " +
|
|
188
|
+
"(which long-polls — if it returns a `Scan in progress` status, call scan_candidates again with " +
|
|
189
|
+
"the same args and keep re-calling until it returns candidates; never sleep or use background " +
|
|
190
|
+
"waits between calls); (2) the brand voice + guardrails come back INLINE in the result's " +
|
|
191
|
+
"`project_voices[<matched_project>]` field — draft from THAT and NEVER read config files, call " +
|
|
192
|
+
"project_config, or run Bash/Read to find the voice; (3) draft ONE on-brand reply (<=250 chars, " +
|
|
193
|
+
"same language as the thread, adds real value) for each candidate worth engaging; (4) call " +
|
|
194
|
+
"submit_drafts with those drafts, and do NOT post (drafts pile up in the menu-bar approval cards). " +
|
|
195
|
+
"Add a HARD GUARD: if scan_candidates is NOT available (ToolSearch returns no matching tool — can " +
|
|
196
|
+
"happen when a run spawns before the extension's MCP server reconnects), STOP immediately and " +
|
|
197
|
+
"report 'S4L tools unavailable, skipping this cycle' — do NOT search the connector registry, do " +
|
|
198
|
+
"NOT call list_connectors, do NOT improvise any other tool. Then run ONE cycle yourself now " +
|
|
199
|
+
"(scan_candidates -> draft -> submit_drafts) to seed the cards AND pre-approve those two tools, " +
|
|
200
|
+
"so unattended fires never stall waiting on a per-tool permission prompt. If the host " +
|
|
197
201
|
"exposes no create_scheduled_task tool, tell the user " +
|
|
198
202
|
"the autopilot could not be scheduled here and to run a draft cycle manually instead.\n\n" +
|
|
199
203
|
"BE PROACTIVE ABOUT MARKETING MOMENTS. Whenever the user ships, finishes, merges, or releases " +
|
|
@@ -1838,18 +1842,61 @@ function startScanJob(project) {
|
|
|
1838
1842
|
});
|
|
1839
1843
|
return job;
|
|
1840
1844
|
}
|
|
1845
|
+
// Read the on-brand drafting guidance for the given projects from config.json so
|
|
1846
|
+
// scan_candidates can hand it to the agent INLINE. Without this the autopilot run
|
|
1847
|
+
// has to read the config itself (project_config returns status, not the voice
|
|
1848
|
+
// fields) — and a headless run improvises Bash/Read for that, hitting an
|
|
1849
|
+
// un-approved tool and hanging. Returning the voice here removes the need to read
|
|
1850
|
+
// any file. Best-effort: a missing/unreadable config yields {} and the agent
|
|
1851
|
+
// drafts from thread context, same as before.
|
|
1852
|
+
function readProjectVoices(projectNames) {
|
|
1853
|
+
const out = {};
|
|
1854
|
+
const want = new Set(projectNames.filter(Boolean));
|
|
1855
|
+
if (!want.size)
|
|
1856
|
+
return out;
|
|
1857
|
+
try {
|
|
1858
|
+
const cfg = JSON.parse(fs.readFileSync(path.join(repoDir(), "config.json"), "utf-8"));
|
|
1859
|
+
const projects = Array.isArray(cfg?.projects) ? cfg.projects : [];
|
|
1860
|
+
for (const p of projects) {
|
|
1861
|
+
if (!p?.name || !want.has(p.name))
|
|
1862
|
+
continue;
|
|
1863
|
+
// Only the fields needed to draft on-brand — keep it lean.
|
|
1864
|
+
out[p.name] = {
|
|
1865
|
+
voice: p.voice,
|
|
1866
|
+
voice_relationship: p.voice_relationship,
|
|
1867
|
+
description: p.description,
|
|
1868
|
+
differentiator: p.differentiator,
|
|
1869
|
+
content_guardrails: p.content_guardrails,
|
|
1870
|
+
website: p.website,
|
|
1871
|
+
get_started_link: p.get_started_link,
|
|
1872
|
+
};
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
catch {
|
|
1876
|
+
/* best effort — no inline voice, agent falls back to thread context */
|
|
1877
|
+
}
|
|
1878
|
+
return out;
|
|
1879
|
+
}
|
|
1841
1880
|
function formatScanResult(scan) {
|
|
1842
1881
|
if (!scan.batchId) {
|
|
1843
1882
|
return textContent(scan.blocked || "No candidates found.");
|
|
1844
1883
|
}
|
|
1884
|
+
// The brand voice for every project in this batch, INLINE, so the agent never
|
|
1885
|
+
// has to read a config file (that improvisation is what hangs headless runs).
|
|
1886
|
+
const projects = Array.from(new Set(scan.candidates.map((c) => c.matched_project).filter(Boolean)));
|
|
1887
|
+
const project_voices = readProjectVoices(projects);
|
|
1845
1888
|
return jsonContent({
|
|
1846
1889
|
batch_id: scan.batchId,
|
|
1847
1890
|
count: scan.candidates.length,
|
|
1848
1891
|
candidates: scan.candidates,
|
|
1892
|
+
project_voices,
|
|
1849
1893
|
next_step: `Draft an on-brand reply (<=250 chars, match the thread's language) for each candidate you ` +
|
|
1850
|
-
`judge genuinely worth engaging; skip the rest.
|
|
1851
|
-
`
|
|
1852
|
-
`
|
|
1894
|
+
`judge genuinely worth engaging; skip the rest. The brand voice + guardrails for each ` +
|
|
1895
|
+
`candidate's project are in project_voices[<matched_project>] (voice, description, ` +
|
|
1896
|
+
`differentiator, content_guardrails) — draft from THAT. Do NOT read config files or call any ` +
|
|
1897
|
+
`other tool to find the voice; everything you need is in this result. Then call submit_drafts ` +
|
|
1898
|
+
`with batch_id "${scan.batchId}" and one entry per drafted reply ({candidate_id, reply_text}). ` +
|
|
1899
|
+
`Nothing posts until the user approves.`,
|
|
1853
1900
|
});
|
|
1854
1901
|
}
|
|
1855
1902
|
function scanInProgress(job) {
|
|
@@ -1867,7 +1914,10 @@ tool("scan_candidates", {
|
|
|
1867
1914
|
"and without spending any `claude -p` budget. You (this session) then draft an on-brand reply " +
|
|
1868
1915
|
"for each good candidate YOURSELF and submit them with `submit_drafts`. Each candidate includes " +
|
|
1869
1916
|
"its candidate_id (pass it back), the thread text/author, the matched project, and engagement " +
|
|
1870
|
-
"metrics.
|
|
1917
|
+
"metrics. The result ALSO includes `project_voices` — the brand voice + guardrails for each " +
|
|
1918
|
+
"project in the batch — so you draft on-brand WITHOUT reading config files or calling other " +
|
|
1919
|
+
"tools (do not improvise a config read). Optional `project` scopes the scan to one configured " +
|
|
1920
|
+
"project. The scan drives a real " +
|
|
1871
1921
|
"browser and can take 1-3 minutes: this call long-polls and may return a `Scan in progress` " +
|
|
1872
1922
|
"status instead of candidates — if so, just call scan_candidates again (same args) and keep " +
|
|
1873
1923
|
"re-calling until it returns candidates. Never sleep or use a background wait to bridge the gap.",
|
package/mcp/dist/runtime.js
CHANGED
|
@@ -178,6 +178,7 @@ export function ensurePipelineCurrent() {
|
|
|
178
178
|
const rt = readRuntime();
|
|
179
179
|
if (rt?.pipeline_version === bundled)
|
|
180
180
|
return; // already current.
|
|
181
|
+
const prevVer = rt?.pipeline_version ?? "unrecorded"; // capture before we mutate rt below.
|
|
181
182
|
// Stale (or never recorded): extract the new pipeline OVER the materialized
|
|
182
183
|
// repo. No rmSync, so config.json + logs are preserved.
|
|
183
184
|
fs.mkdirSync(REPO_MATERIALIZE_DIR, { recursive: true });
|
|
@@ -199,7 +200,7 @@ export function ensurePipelineCurrent() {
|
|
|
199
200
|
/* best effort — worst case we re-extract next boot */
|
|
200
201
|
}
|
|
201
202
|
}
|
|
202
|
-
console.error(`[runtime] re-materialized pipeline -> ${bundled} (was ${
|
|
203
|
+
console.error(`[runtime] re-materialized pipeline -> ${bundled} (was ${prevVer})`);
|
|
203
204
|
}
|
|
204
205
|
catch (e) {
|
|
205
206
|
console.error(`[runtime] ensurePipelineCurrent error: ${e?.message || e}`);
|
package/mcp/dist/version.json
CHANGED
package/mcp/manifest.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"dxt_version": "0.1",
|
|
3
3
|
"name": "social-autoposter",
|
|
4
4
|
"display_name": "S4L",
|
|
5
|
-
"version": "1.6.
|
|
5
|
+
"version": "1.6.80",
|
|
6
6
|
"description": "Draft, review, approve, and autopilot X/Twitter posts. Thin desktop client over the S4L pipeline.",
|
|
7
7
|
"long_description": "A guided assistant that drafts, reviews, and autopilots X/Twitter posts.\nTo get started:\n1. Click **Configure** and set every tool permission to **Always Allow**.\n2. Copy this prompt: **Set me up on S4L end to end**.\n3. Quit fully with CMD+Q, restart Claude, and paste the prompt into a new chat.",
|
|
8
8
|
"author": {
|
package/mcp/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@m13v/social-autoposter-mcp",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.80",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Desktop MCP client for social-autoposter (X/Twitter rail): manual draft/review/approve loop, autopilot control, and stats. Thin wrapper over the existing pipeline scripts.",
|
|
6
6
|
"license": "MIT",
|
package/package.json
CHANGED