social-autoposter 1.6.44 → 1.6.46
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 +57 -13
- package/package.json +1 -1
package/mcp/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ import { z } from "zod";
|
|
|
16
16
|
import os from "node:os";
|
|
17
17
|
import path from "node:path";
|
|
18
18
|
import fs from "node:fs";
|
|
19
|
-
import { REPO_DIR, runPython, run, readPlan, writePlan, planPath,
|
|
19
|
+
import { REPO_DIR, runPython, run, readPlan, writePlan, planPath, } from "./repo.js";
|
|
20
20
|
import { applySetup, resolveProject, hasReadyProject, listManagedProjectStatus, REQUIRED_FIELDS, RECOMMENDED_FIELDS, CONFIG_PATH, } from "./setup.js";
|
|
21
21
|
import { xStatus, xConnect, summarizeXAuth } from "./twitterAuth.js";
|
|
22
22
|
import { VERSION, versionStatus, latestPublishedVersion } from "./version.js";
|
|
@@ -180,7 +180,8 @@ function cycleProgressMessage(line) {
|
|
|
180
180
|
let m;
|
|
181
181
|
if (/=== Twitter Cycle \(batch=/.test(l))
|
|
182
182
|
return "Starting draft cycle…";
|
|
183
|
-
|
|
183
|
+
// NB: lines carry a `[HH:MM:SS] ` timestamp prefix, so don't anchor on ^.
|
|
184
|
+
if ((m = /Selected projects?:\s*(.+)$/.exec(l)))
|
|
184
185
|
return `Selected project: ${m[1]}`;
|
|
185
186
|
if (/phase=phase1\b/.test(l) || /Phase 1: drafting queries/.test(l))
|
|
186
187
|
return "Searching X for fresh threads…";
|
|
@@ -206,28 +207,67 @@ async function produceDrafts(project, onProgress) {
|
|
|
206
207
|
const env = {
|
|
207
208
|
DRAFT_ONLY: "1",
|
|
208
209
|
TWITTER_PAGE_GEN_RATE: "0",
|
|
210
|
+
// Interactive draft_cycle: launch the harness Chrome ON-SCREEN so the user
|
|
211
|
+
// can watch the scan/scrape happen live. Cron/autopilot do NOT set these, so
|
|
212
|
+
// background runs keep the off-screen default in twitter-backend.sh and don't
|
|
213
|
+
// hijack the screen. (Only affects a fresh Chrome launch; an already-running
|
|
214
|
+
// harness window keeps its current position.)
|
|
215
|
+
BH_WINDOW_POS: "60,60",
|
|
216
|
+
BH_WINDOW_SIZE: "1280,900",
|
|
209
217
|
};
|
|
210
218
|
if (project)
|
|
211
219
|
env.SAPS_FORCE_PROJECT = project;
|
|
212
220
|
let step = 0;
|
|
221
|
+
let lastMsg = "";
|
|
222
|
+
// ONE predictable, host-independent place to watch a draft_cycle run, so any
|
|
223
|
+
// agent (or human) debugging "the cycle looks stuck" has an obvious path:
|
|
224
|
+
// ~/social-autoposter/skill/logs/draft_cycle-mcp.log
|
|
225
|
+
// It lives right next to the cycle's own twitter-cycle-*.log. We append the
|
|
226
|
+
// full live cycle output here (not just milestones) plus a clear run banner.
|
|
227
|
+
// Best-effort: a logging failure must never break the cycle.
|
|
228
|
+
const mcpLog = path.join(REPO_DIR, "skill", "logs", "draft_cycle-mcp.log");
|
|
229
|
+
const appendLog = (s) => {
|
|
230
|
+
try {
|
|
231
|
+
fs.appendFileSync(mcpLog, s);
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
/* ignore — never fail the cycle over a log write */
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
try {
|
|
238
|
+
fs.mkdirSync(path.dirname(mcpLog), { recursive: true });
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
/* ignore */
|
|
242
|
+
}
|
|
243
|
+
appendLog(`\n===== draft_cycle start ${new Date().toISOString()} ` +
|
|
244
|
+
`project=${project ?? "(default)"} =====\n`);
|
|
213
245
|
const res = await run("bash", ["skill/run-twitter-cycle.sh"], {
|
|
214
246
|
env,
|
|
215
247
|
timeoutMs: 900_000, // scan+draft can take several minutes
|
|
216
|
-
//
|
|
217
|
-
//
|
|
218
|
-
//
|
|
219
|
-
//
|
|
248
|
+
// Fan every cycle line out to THREE sinks so progress is never a black box:
|
|
249
|
+
// 1. draft_cycle-mcp.log — the stable, documented, host-independent file.
|
|
250
|
+
// 2. this server's stderr — lands in the host's MCP server log
|
|
251
|
+
// (mcp-server-social-autoposter.log on Desktop), which used to show
|
|
252
|
+
// only the JSON-RPC handshake.
|
|
253
|
+
// 3. the live progress sink — milestone messages under the chat spinner.
|
|
220
254
|
onLine: (line) => {
|
|
221
255
|
const t = line.replace(/\s+$/, "");
|
|
222
|
-
if (t.trim())
|
|
256
|
+
if (t.trim()) {
|
|
257
|
+
appendLog(`${t}\n`);
|
|
223
258
|
console.error(`[draft_cycle] ${t}`);
|
|
259
|
+
}
|
|
224
260
|
if (!onProgress)
|
|
225
261
|
return;
|
|
226
262
|
const msg = cycleProgressMessage(t);
|
|
227
|
-
|
|
263
|
+
// Skip consecutive duplicates (a phase can log a couple matching lines).
|
|
264
|
+
if (msg && msg !== lastMsg) {
|
|
265
|
+
lastMsg = msg;
|
|
228
266
|
onProgress(msg, ++step);
|
|
267
|
+
}
|
|
229
268
|
},
|
|
230
269
|
});
|
|
270
|
+
appendLog(`===== draft_cycle end ${new Date().toISOString()} exit=${res.code} =====\n`);
|
|
231
271
|
// Prefer the explicit marker; fall back to the newest plan file on disk.
|
|
232
272
|
const marker = /DRAFT_ONLY_PLAN=\/tmp\/twitter_cycle_plan_(.+)\.json/.exec(res.stdout + "\n" + res.stderr);
|
|
233
273
|
if (marker && marker[1])
|
|
@@ -239,13 +279,17 @@ async function produceDrafts(project, onProgress) {
|
|
|
239
279
|
if (blockedMarker && blockedMarker[1]) {
|
|
240
280
|
return { batchId: null, blocked: blockedReasonMessage(blockedMarker[1]) };
|
|
241
281
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
282
|
+
// No `DRAFT_ONLY_PLAN=` marker from THIS run => this run produced no drafts.
|
|
283
|
+
// We MUST NOT fall back to the newest plan file on disk (`latestBatchId()`):
|
|
284
|
+
// that's a *previous* run's batch, so a 5-second empty cycle would echo an old
|
|
285
|
+
// 7-draft batch and report phantom success. Report 0 drafts honestly, with the
|
|
286
|
+
// pipeline's own reason (e.g. cold-start project with no seeded queries).
|
|
245
287
|
return {
|
|
246
288
|
batchId: null,
|
|
247
|
-
blocked: `
|
|
248
|
-
`
|
|
289
|
+
blocked: `This run produced no drafts (exit ${res.code}). The scan found no fresh ` +
|
|
290
|
+
`candidates for the selected project — usually a cold-start project with ` +
|
|
291
|
+
`no seeded search queries/topics, or a pipeline error. This is NOT a ` +
|
|
292
|
+
`previous batch. Tail:\n` +
|
|
249
293
|
res.stderr.split("\n").slice(-12).join("\n"),
|
|
250
294
|
};
|
|
251
295
|
}
|
package/package.json
CHANGED