social-autoposter 1.6.152 → 1.6.153

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.
@@ -1,4 +1,4 @@
1
1
  {
2
- "version": "1.6.152",
3
- "installedAt": "2026-06-29T22:42:31.815Z"
2
+ "version": "1.6.153",
3
+ "installedAt": "2026-06-29T22:59:53.681Z"
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": "S4L",
5
- "version": "1.6.152",
5
+ "version": "1.6.153",
6
6
  "description": "Draft, review, approve, and autopilot X/Twitter posts.",
7
7
  "long_description": "The disclaimer above is generic Claude boilerplate. S4L is an open source product developed by Mediar.ai Incorporated, a VC-backed San Francisco-based startup.\n\nTo get started:\n\n1\\. Copy this prompt: **Set me up on S4L end to end**\n\n2\\. Quit fully with CMD+Q, restart Claude, and paste the prompt into a new chat.",
8
8
  "author": {
@@ -143,6 +143,31 @@ AUTOPILOT_RUNNING_STALL_SECONDS = 900
143
143
  # truth, scripts/schedule_state.py (FIRING_WINDOW there). _schedule_state delegates
144
144
  # to it, so it is intentionally NOT redefined here.
145
145
 
146
+ # How long the producer can sit narrating "drafting replies (Nm)" before we treat
147
+ # the draft as STUCK rather than healthy. The producer writes that label the whole
148
+ # time it blocks waiting for a worker to return a result (up to its 30-min queue
149
+ # timeout). A healthy drain clears in ~1-2 min; if the label has been "drafting"
150
+ # this long, the worker keeps dying mid-run (host inactivity-kill) or never claims,
151
+ # and nothing is draining — so we flip the menu bar from a reassuring spinner to
152
+ # ⚠ instead of letting the stale "drafting (8m)" lie persist. Well above any
153
+ # healthy single drain (the worker itself dies at ~2 min today).
154
+ DRAFT_STUCK_SECONDS = 300
155
+
156
+
157
+ def _label_elapsed_secs(label):
158
+ """Parse the trailing duration the producer encodes in a drafting activity
159
+ label — 'drafting replies (8m)', '... (queued 18m)', '... (45s)' — into
160
+ seconds. Returns 0 when there's no parseable duration. _fmt_dur (claude_job.py)
161
+ only ever emits '<n>s' (<60s) or '<n>m', so this mirror stays trivial."""
162
+ if not label:
163
+ return 0
164
+ import re
165
+ matches = re.findall(r"(\d+)\s*([sm])\b", str(label))
166
+ if not matches:
167
+ return 0
168
+ n, unit = matches[-1]
169
+ return int(n) * (60 if unit == "m" else 1)
170
+
146
171
 
147
172
  def _glyph(status):
148
173
  return GLYPH.get(status, "·")
@@ -1013,6 +1038,22 @@ class S4LMenuBar(rumps.App):
1013
1038
  attention = True
1014
1039
  else:
1015
1040
  self._stall_reason_info = ("", "")
1041
+ # Draft worker stuck/killed: the producer narrates "drafting replies (Nm)"
1042
+ # the whole time it blocks waiting for a worker to return a result, with NO
1043
+ # idea the worker died. A healthy drain clears in ~1-2 min; once that label
1044
+ # has been "drafting" past DRAFT_STUCK_SECONDS the worker keeps getting
1045
+ # killed mid-run (or never claims) and nothing is draining — flip to ⚠
1046
+ # instead of leaving the reassuring "drafting (8m)" spinner up. Skip when a
1047
+ # more specific cause (rate limit) already owns the reason.
1048
+ if setup_complete and self._stall_reason_info[0] != "rate_limited":
1049
+ _act = st.read_activity()
1050
+ if (
1051
+ _act
1052
+ and _act.get("state") == "drafting"
1053
+ and _label_elapsed_secs(_act.get("label")) >= DRAFT_STUCK_SECONDS
1054
+ ):
1055
+ attention = True
1056
+ self._stall_reason_info = ("draft_stuck", _act.get("label") or "")
1016
1057
  # Drop the stale "drafting" spinner while we need attention so the ⚠ shows.
1017
1058
  self._stalled = attention
1018
1059
 
@@ -1350,6 +1391,14 @@ class S4LMenuBar(rumps.App):
1350
1391
  items.append(self._label(
1351
1392
  " " + (self._stall_reason_info[1] or "wait for reset or switch account")
1352
1393
  ))
1394
+ elif self._stall_reason_info[0] == "draft_stuck":
1395
+ # Routines fire and the producer keeps narrating "drafting" but the
1396
+ # worker keeps getting killed mid-run / never returns a result. Don't
1397
+ # offer Re-arm (routines are fine); state the real problem.
1398
+ items.append(self._label("⚠ Draft not completing — worker keeps getting killed"))
1399
+ items.append(self._label(
1400
+ " " + (self._stall_reason_info[1] or "drafting") + " — no result yet"
1401
+ ))
1353
1402
  elif schedule_state == "disabled":
1354
1403
  items.append(self._label("⚠ Draft tasks are scheduled but disabled"))
1355
1404
  items.append(rumps.MenuItem("Set up draft schedule for this account", callback=self._rearm))
package/mcp/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m13v/social-autoposter-mcp",
3
- "version": "1.6.152",
3
+ "version": "1.6.153",
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "social-autoposter",
3
- "version": "1.6.152",
3
+ "version": "1.6.153",
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"