social-autoposter 1.6.73 → 1.6.74

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 CHANGED
@@ -35,6 +35,10 @@ const PANEL_URI = "ui://social-autoposter/panel.html";
35
35
  // continuous autopilot instead of each run overwriting the last; post_drafts posts
36
36
  // the approved subset and marks them posted (filtered out of the cards thereafter).
37
37
  const REVIEW_QUEUE_ID = "review-queue";
38
+ // The Desktop scheduled task onboarding creates for the autopilot. Its presence on
39
+ // disk is the single "autopilot is set up" signal the dashboard + menu bar share
40
+ // (the legacy launchd autopilot is retired).
41
+ const AUTOPILOT_TASK_ID = "social-autoposter-autopilot";
38
42
  const TWITTER_AUTOPILOT_LABEL = "com.m13v.social-twitter-cycle";
39
43
  const TWITTER_AUTOPILOT_PLIST = path.join(os.homedir(), "Library", "LaunchAgents", `${TWITTER_AUTOPILOT_LABEL}.plist`);
40
44
  // Daily self-updater. Enabled alongside autopilot so a hands-free (headless)
@@ -1354,18 +1358,28 @@ function runtimeSnapshot() {
1354
1358
  // and re-reads status. The tool itself returns the first-paint snapshot so the
1355
1359
  // view has data the instant it loads.
1356
1360
  // Is either launchd job (cycle / daily updater) currently loaded?
1361
+ // "Autopilot" is now the Claude Desktop scheduled task `social-autoposter-autopilot`
1362
+ // (created during onboarding via create_scheduled_task), NOT the legacy launchd job.
1363
+ // We can't read the host's enabled/paused flag, but the task's presence on disk is the
1364
+ // single signal the dashboard AND the menu bar key off of, so they stay aligned.
1357
1365
  async function autopilotLoaded() {
1366
+ let autopilot_on = false;
1367
+ try {
1368
+ const cfg = process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), ".claude");
1369
+ autopilot_on = fs.existsSync(path.join(cfg, "scheduled-tasks", AUTOPILOT_TASK_ID, "SKILL.md"));
1370
+ }
1371
+ catch {
1372
+ /* leave false */
1373
+ }
1374
+ let auto_update_on = false;
1358
1375
  try {
1359
1376
  const res = await run("launchctl", ["list"], { timeoutMs: 10_000 });
1360
- const lines = res.stdout.split("\n");
1361
- return {
1362
- autopilot_on: lines.some((l) => l.includes(TWITTER_AUTOPILOT_LABEL)),
1363
- auto_update_on: lines.some((l) => l.includes(UPDATER_LABEL)),
1364
- };
1377
+ auto_update_on = res.stdout.split("\n").some((l) => l.includes(UPDATER_LABEL));
1365
1378
  }
1366
1379
  catch {
1367
- return { autopilot_on: false, auto_update_on: false };
1380
+ /* leave false */
1368
1381
  }
1382
+ return { autopilot_on, auto_update_on };
1369
1383
  }
1370
1384
  // Assemble everything the panel needs in one shot (projects + X + autopilot +
1371
1385
  // version). Resilient: any probe that throws degrades to a safe default rather
@@ -1,4 +1,4 @@
1
1
  {
2
- "version": "1.6.72",
3
- "installedAt": "2026-06-20T17:17:17.565Z"
2
+ "version": "1.6.73",
3
+ "installedAt": "2026-06-20T18:16:22.534Z"
4
4
  }
package/mcp/manifest.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "dxt_version": "0.1",
3
3
  "name": "social-autoposter",
4
4
  "display_name": "Social Autoposter",
5
- "version": "1.6.72",
5
+ "version": "1.6.73",
6
6
  "description": "Draft, review, approve, and autopilot X/Twitter posts. Thin desktop client over the social-autoposter pipeline.",
7
7
  "long_description": "A guided assistant that drafts, reviews, and autopilots X/Twitter posts.\nTo get started:\n1. Fully quit and restart Claude (quit and reopen, not just close the window).\n2. Choose **Set up social-autoposter** from the prompt menu or type **Set me up on social-autoposter end to end**. The agent installs the owned runtime, connects X, discovers and configures your product, and verifies with a draft-only cycle.",
8
8
  "author": {
@@ -191,12 +191,8 @@ class S4LMenuBar(rumps.App):
191
191
  except Exception:
192
192
  pass
193
193
 
194
- def _toggle_ap(self, sender):
195
- desired = not bool(sender.state)
196
- if st.set_autopilot(desired):
197
- sender.state = 1 if desired else 0
198
- else:
199
- self._notify("S4L", "Open Claude Desktop to change autopilot.")
194
+ # _toggle_ap removed: autopilot is the Claude Desktop scheduled task now, managed
195
+ # in the Scheduled tab. The menu bar mirrors the dashboard (no launchd toggle).
200
196
 
201
197
  # ---- activity spinner -------------------------------------------------
202
198
  # The server writes activity.json while a tool runs (scanning/drafting/
@@ -469,9 +465,6 @@ class S4LMenuBar(rumps.App):
469
465
  out.append(self._label("7d stats — open dashboard"))
470
466
 
471
467
  out.append(rumps.separator)
472
- ap = rumps.MenuItem("Autopilot", callback=self._toggle_ap)
473
- ap.state = 1 if snap.get("autopilot_on") else 0
474
- out.append(ap)
475
468
  out.append(
476
469
  rumps.MenuItem("Run draft cycle in Claude", callback=self._draft)
477
470
  )
@@ -103,7 +103,11 @@ def _launchctl_list() -> str:
103
103
 
104
104
 
105
105
  def autopilot_loaded() -> bool:
106
- return AUTOPILOT_LABEL in _launchctl_list()
106
+ # Autopilot is now the Claude Desktop scheduled task, not the legacy launchd job.
107
+ cfg = os.environ.get("CLAUDE_CONFIG_DIR") or os.path.join(str(Path.home()), ".claude")
108
+ return os.path.exists(
109
+ os.path.join(cfg, "scheduled-tasks", "social-autoposter-autopilot", "SKILL.md")
110
+ )
107
111
 
108
112
 
109
113
  # ---- loopback panel server (live, when Claude Desktop is running) ----------
@@ -207,35 +211,9 @@ def stats_7d():
207
211
  }
208
212
 
209
213
 
210
- def set_autopilot(enable: bool) -> bool:
211
- """Toggle background posting. Prefer the loopback tool (it creates the plist
212
- correctly on first enable); fall back to launchctl against the existing
213
- plist when Claude Desktop is closed. Returns False if it couldn't act."""
214
- res = loopback_tool("autopilot", {"action": "enable" if enable else "disable"})
215
- if res is not None:
216
- return True
217
- plist = str(
218
- Path.home() / "Library" / "LaunchAgents" / (AUTOPILOT_LABEL + ".plist")
219
- )
220
- uid = os.getuid()
221
- try:
222
- if enable:
223
- if not os.path.exists(plist):
224
- return False # first enable needs the server to write the plist
225
- subprocess.run(
226
- ["launchctl", "bootstrap", f"gui/{uid}", plist],
227
- capture_output=True,
228
- timeout=15,
229
- )
230
- else:
231
- subprocess.run(
232
- ["launchctl", "bootout", f"gui/{uid}/{AUTOPILOT_LABEL}"],
233
- capture_output=True,
234
- timeout=15,
235
- )
236
- return True
237
- except Exception:
238
- return False
214
+ # set_autopilot() (the launchd toggle) was removed: the autopilot is now the Claude
215
+ # Desktop scheduled task `social-autoposter-autopilot`, managed in the Scheduled tab,
216
+ # so the menu bar no longer toggles a launchd job (it mirrors the dashboard instead).
239
217
 
240
218
 
241
219
  def panel_url():
package/mcp/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m13v/social-autoposter-mcp",
3
- "version": "1.6.72",
3
+ "version": "1.6.73",
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
  "type": "module",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "social-autoposter",
3
- "version": "1.6.73",
3
+ "version": "1.6.74",
4
4
  "description": "Automated social posting pipeline for Reddit, X/Twitter, LinkedIn, and Moltbook. Install as a Claude Code agent skill.",
5
5
  "bin": {
6
6
  "social-autoposter": "bin/cli.js"