social-autoposter 1.6.148 → 1.6.150
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 +54 -2
- package/mcp/dist/panel.html +23 -12
- package/mcp/dist/version.json +2 -2
- package/mcp/manifest.json +1 -1
- package/mcp/menubar/s4l_menubar.py +46 -75
- package/mcp/package.json +1 -1
- package/package.json +1 -1
- package/scripts/_scan_pending_detail.py +33 -0
package/mcp/dist/index.js
CHANGED
|
@@ -464,6 +464,14 @@ async function produceDrafts(project, onProgress) {
|
|
|
464
464
|
await ensureOverlayWatch();
|
|
465
465
|
let step = 0;
|
|
466
466
|
let lastMsg = "";
|
|
467
|
+
// Granular scan progress for the menu-bar label. Phase 1 logs one
|
|
468
|
+
// `executing N queries` line (the total), then one `ok/err project=… kept=K`
|
|
469
|
+
// line per query. We count those to paint `scanning X · N/M · kept K` instead
|
|
470
|
+
// of a static "scanning X". Best-effort: missing total falls back to a plain
|
|
471
|
+
// count, and any parse miss just leaves the prior label up.
|
|
472
|
+
let scanTotal = 0;
|
|
473
|
+
let scanDone = 0;
|
|
474
|
+
let scanKept = 0;
|
|
467
475
|
// ONE predictable, host-independent place to watch a draft_cycle run, so any
|
|
468
476
|
// agent (or human) debugging "the cycle looks stuck" has an obvious path:
|
|
469
477
|
// ~/social-autoposter/skill/logs/draft_cycle-mcp.log
|
|
@@ -505,6 +513,21 @@ async function produceDrafts(project, onProgress) {
|
|
|
505
513
|
appendLog(`${t}\n`);
|
|
506
514
|
console.error(`[draft_cycle] ${t}`);
|
|
507
515
|
}
|
|
516
|
+
// Per-query scan progress -> granular menu-bar label. These lines only
|
|
517
|
+
// appear during Phase 1 (before 2b-prep), so they never fight the
|
|
518
|
+
// "drafting" label below.
|
|
519
|
+
let sm;
|
|
520
|
+
if ((sm = /executing (\d+) quer/.exec(t))) {
|
|
521
|
+
scanTotal = parseInt(sm[1], 10) || 0;
|
|
522
|
+
}
|
|
523
|
+
else if ((sm = /^\s*(?:ok|err)\s+project=/.exec(t))) {
|
|
524
|
+
scanDone += 1;
|
|
525
|
+
const km = /kept=(\d+)/.exec(t);
|
|
526
|
+
if (km)
|
|
527
|
+
scanKept += parseInt(km[1], 10) || 0;
|
|
528
|
+
const prog = scanTotal ? `${scanDone}/${scanTotal}` : `${scanDone}`;
|
|
529
|
+
writeActivity("scanning", `scanning X · ${prog} · kept ${scanKept}`);
|
|
530
|
+
}
|
|
508
531
|
if (/Phase 2b-prep/.test(t))
|
|
509
532
|
writeActivity("drafting", "drafting replies");
|
|
510
533
|
if (!onProgress)
|
|
@@ -1014,9 +1037,9 @@ tool("engagement_mode", {
|
|
|
1014
1037
|
"toggle.",
|
|
1015
1038
|
inputSchema: {
|
|
1016
1039
|
action: z
|
|
1017
|
-
.enum(["get", "set"])
|
|
1040
|
+
.enum(["get", "set", "toggle"])
|
|
1018
1041
|
.optional()
|
|
1019
|
-
.describe("get = read current mode + persona status. set = record the user's chosen mode."),
|
|
1042
|
+
.describe("get = read current mode + persona status. set = record the user's chosen mode (provisions the persona). toggle = lightweight flip promotion<->personal_brand (mode.json only, no persona work) — the dashboard/menu-bar quick toggle."),
|
|
1020
1043
|
mode: z
|
|
1021
1044
|
.enum(["personal_brand", "promotion"])
|
|
1022
1045
|
.optional()
|
|
@@ -1047,6 +1070,20 @@ tool("engagement_mode", {
|
|
|
1047
1070
|
const persona = findPersonaProject();
|
|
1048
1071
|
return jsonContent({ mode, persona: persona ? persona.name : null });
|
|
1049
1072
|
}
|
|
1073
|
+
// Lightweight flip (the dashboard/menu-bar quick toggle): just rewrite
|
|
1074
|
+
// mode.json via saps_mode.py — NO persona provisioning. Mirrors the menu
|
|
1075
|
+
// bar's pure-local _toggle_mode so flipping from either surface is cheap.
|
|
1076
|
+
if (action === "toggle") {
|
|
1077
|
+
const cur = await runPython("scripts/saps_mode.py", ["get"], { timeoutMs: 15_000 });
|
|
1078
|
+
const now = (cur.stdout || "").trim() || "promotion";
|
|
1079
|
+
const next = now === "personal_brand" ? "promotion" : "personal_brand";
|
|
1080
|
+
const res = await runPython("scripts/saps_mode.py", ["set", next], { timeoutMs: 15_000 });
|
|
1081
|
+
if (res.code !== 0) {
|
|
1082
|
+
const tail = (res.stderr || res.stdout).trim().split("\n").slice(-1)[0] || "unknown error";
|
|
1083
|
+
return textContent(`Could not switch mode: ${tail}`);
|
|
1084
|
+
}
|
|
1085
|
+
return jsonContent({ mode: next });
|
|
1086
|
+
}
|
|
1050
1087
|
const mode = args.mode;
|
|
1051
1088
|
if (mode !== "personal_brand" && mode !== "promotion") {
|
|
1052
1089
|
return textContent("Ask the user which they want, then call again with mode:'personal_brand' (organic brand " +
|
|
@@ -1412,6 +1449,7 @@ tool("project_config", {
|
|
|
1412
1449
|
mcp_version: ver.installed,
|
|
1413
1450
|
latest_version: ver.latest,
|
|
1414
1451
|
update_available: ver.update_available,
|
|
1452
|
+
mode: currentMode(),
|
|
1415
1453
|
update_hint: ver.update_available
|
|
1416
1454
|
? `A newer version (${ver.latest}) is available — you're on ${ver.installed}. ` +
|
|
1417
1455
|
`Tell the user and offer to run the \`runtime\` tool with action:'update' ` +
|
|
@@ -2730,6 +2768,8 @@ async function buildSnapshot() {
|
|
|
2730
2768
|
runtime_ready: rtReady,
|
|
2731
2769
|
runtime_provisioning: isProvisioning(),
|
|
2732
2770
|
setup_complete: setupComplete,
|
|
2771
|
+
// Engagement mode for display in BOTH surfaces (single source: mode.json).
|
|
2772
|
+
mode: currentMode(),
|
|
2733
2773
|
onboarding: onboardingLive,
|
|
2734
2774
|
};
|
|
2735
2775
|
// Persist this snapshot so the menu bar can answer "set up?" the SAME way when
|
|
@@ -2892,6 +2932,18 @@ function modeChosen() {
|
|
|
2892
2932
|
return false;
|
|
2893
2933
|
}
|
|
2894
2934
|
}
|
|
2935
|
+
// The current engagement mode ('promotion' | 'personal_brand'), surfaced in the
|
|
2936
|
+
// snapshot so the dashboard AND menu bar read it from ONE place (mode.json, the
|
|
2937
|
+
// same file saps_mode.py writes). Defaults to promotion when unset.
|
|
2938
|
+
function currentMode() {
|
|
2939
|
+
try {
|
|
2940
|
+
const m = (JSON.parse(fs.readFileSync(path.join(sapsStateDir(), "mode.json"), "utf-8")).mode || "").trim();
|
|
2941
|
+
return m === "personal_brand" ? "personal_brand" : "promotion";
|
|
2942
|
+
}
|
|
2943
|
+
catch {
|
|
2944
|
+
return "promotion";
|
|
2945
|
+
}
|
|
2946
|
+
}
|
|
2895
2947
|
// ---- Cross-instance "posting active" flag ----------------------------------
|
|
2896
2948
|
// posting-active.json in the shared state dir is the CROSS-MCP-INSTANCE version
|
|
2897
2949
|
// of the in-process `postingActive` flag. The autopilot scan and the post
|