social-autoposter 1.6.64 → 1.6.66

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
@@ -20,7 +20,7 @@ import fs from "node:fs";
20
20
  import { repoDir, runPython, run, readPlan, writePlan, planPath, } from "./repo.js";
21
21
  import { applySetup, resolveProject, hasReadyProject, listManagedProjectStatus, REQUIRED_FIELDS, RECOMMENDED_FIELDS, configPath, } from "./setup.js";
22
22
  import { xStatus, xConnect, xDetectSources, xScanProfile, summarizeXAuth } from "./twitterAuth.js";
23
- import { startProvisioning, isProvisioning, readProgress, runtimeReady, readRuntime, resolvePython, } from "./runtime.js";
23
+ import { startProvisioning, isProvisioning, readProgress, runtimeReady, readRuntime, resolvePython, resolveChrome, } from "./runtime.js";
24
24
  import { VERSION, versionStatus, latestPublishedVersion } from "./version.js";
25
25
  import { registerAppTool, registerAppResource, RESOURCE_MIME_TYPE, getUiCapability, } from "@modelcontextprotocol/ext-apps/server";
26
26
  import { fileURLToPath } from "node:url";
@@ -47,8 +47,38 @@ const LAUNCHD_PATH = [
47
47
  "/usr/sbin",
48
48
  "/sbin",
49
49
  ].join(":");
50
+ // Bin dirs the pipeline must resolve FIRST: the owned uv venv (so the scripts'
51
+ // bare `python3` hits the provisioned interpreter with pipeline deps, not the
52
+ // user's system python) and ~/.local/bin (so `browser-harness`, the CDP scan
53
+ // engine, resolves). resolvePython() is dynamic, so this re-derives per call.
54
+ function ownedBinDirs() {
55
+ const dirs = [];
56
+ const py = resolvePython();
57
+ if (path.isAbsolute(py))
58
+ dirs.push(path.dirname(py));
59
+ dirs.push(path.join(os.homedir(), ".local", "bin"));
60
+ return dirs;
61
+ }
62
+ // PATH for an interactively-spawned pipeline run (draft_cycle): owned bins
63
+ // first, then whatever PATH the MCP server inherited.
64
+ function pipelinePath() {
65
+ return [...ownedBinDirs(), process.env.PATH || LAUNCHD_PATH].join(":");
66
+ }
67
+ // PATH baked into launchd plists (autopilot/cron): owned bins first, then the
68
+ // sane launchd default (launchd starts with a bare PATH).
69
+ function launchdPath() {
70
+ return [...ownedBinDirs(), LAUNCHD_PATH].join(":");
71
+ }
50
72
  function plistXml(opts) {
51
73
  const args = opts.programArgs.map((a) => `\t\t<string>${a}</string>`).join("\n");
74
+ // Background (cron/autopilot) runs get the same Chrome the interactive cycle
75
+ // uses, so a no-sudo ~/Applications install (which the shell's own resolver
76
+ // doesn't scan) is still found off-screen. Omitted when Chrome resolves via
77
+ // PATH, so the shell's _resolve_chrome_bin stays the fallback.
78
+ const chrome = resolveChrome();
79
+ const chromeEnv = chrome
80
+ ? `\n\t\t<key>BH_CHROME_BIN</key>\n\t\t<string>${chrome}</string>`
81
+ : "";
52
82
  return `<?xml version="1.0" encoding="UTF-8"?>
53
83
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
54
84
  <plist version="1.0">
@@ -68,13 +98,13 @@ ${args}
68
98
  \t<key>EnvironmentVariables</key>
69
99
  \t<dict>
70
100
  \t\t<key>PATH</key>
71
- \t\t<string>${LAUNCHD_PATH}</string>
101
+ \t\t<string>${launchdPath()}</string>
72
102
  \t\t<key>HOME</key>
73
103
  \t\t<string>${os.homedir()}</string>
74
104
  \t\t<key>SAPS_REPO_DIR</key>
75
105
  \t\t<string>${repoDir()}</string>
76
106
  \t\t<key>SAPS_PYTHON</key>
77
- \t\t<string>${resolvePython()}</string>
107
+ \t\t<string>${resolvePython()}</string>${chromeEnv}
78
108
  \t</dict>
79
109
  \t<key>RunAtLoad</key>
80
110
  \t<${opts.runAtLoad ? "true" : "false"}/>
@@ -256,6 +286,12 @@ async function produceDrafts(project, onProgress) {
256
286
  const env = {
257
287
  DRAFT_ONLY: "1",
258
288
  TWITTER_PAGE_GEN_RATE: "0",
289
+ // Point the cycle at the resolved repo (a bare .mcpb materializes it under
290
+ // the state dir, NOT ~/social-autoposter); run-twitter-cycle.sh honors
291
+ // SAPS_REPO_DIR for its REPO_DIR. And put the owned runtime + ~/.local/bin
292
+ // first on PATH so the script's bare `python3` and `browser-harness` resolve.
293
+ SAPS_REPO_DIR: repoDir(),
294
+ PATH: pipelinePath(),
259
295
  // Interactive draft_cycle: launch the harness Chrome ON-SCREEN so the user
260
296
  // can watch the scan/scrape happen live. Cron/autopilot do NOT set these, so
261
297
  // background runs keep the off-screen default in twitter-backend.sh and don't
@@ -266,6 +302,14 @@ async function produceDrafts(project, onProgress) {
266
302
  };
267
303
  if (project)
268
304
  env.SAPS_FORCE_PROJECT = project;
305
+ // Point the harness at the Chrome the runtime detected/installed. The cycle's
306
+ // own _resolve_chrome_bin doesn't scan ~/Applications (our no-sudo fallback
307
+ // install target), so without this a non-admin .mcpb install would have Chrome
308
+ // on disk yet still report "no Chrome/Chromium binary found." Only set when
309
+ // resolved; otherwise let the shell resolve Chrome from its own probe list.
310
+ const chrome = resolveChrome();
311
+ if (chrome)
312
+ env.BH_CHROME_BIN = chrome;
269
313
  // Bring the on-screen overlay up alongside the live harness window so the user
270
314
  // watching the scan/scrape sees status + queued drafts. Idempotent + detached.
271
315
  await ensureOverlayWatch();
@@ -594,7 +638,17 @@ tool("setup", {
594
638
  "cookies from your everyday browser (Chrome/Arc/Brave/Edge, auto-detected) into it, and " +
595
639
  "(3) verify you're logged in. No other site's cookies are read, and your passwords are never " +
596
640
  "seen. If it can't import a valid session, a Chrome window will open for you to sign in once.",
597
- how_to_proceed: "Tell the user the above in your own words and ask if that's OK. If yes, call setup again with " +
641
+ keychain_prompt: "Reading the saved session requires macOS to unlock the browser's encrypted cookie store, so " +
642
+ "one or more keychain prompts will appear (\u201c... wants to use your confidential information " +
643
+ "stored in '... Safe Storage' in your keychain\u201d). This is expected. The user enters their Mac " +
644
+ "login password and clicks Allow (or Always Allow to avoid repeats). If they use more than one " +
645
+ "browser, the prompt can appear a few times, once per browser.",
646
+ say_to_user: "Heads up: your Mac will pop up a keychain prompt asking to use your browser's Safe Storage. " +
647
+ "That's just us reading your saved X login, nothing else. Type your Mac login password and click " +
648
+ "Allow (or Always Allow). If you use more than one browser you may see it a couple of times, " +
649
+ "once per browser.",
650
+ how_to_proceed: "Tell the user what_will_happen in your own words, then relay the say_to_user line so they know " +
651
+ "the keychain prompt is coming and what to click. Ask if that's OK. If yes, call setup again with " +
598
652
  "action:'connect_x', confirm:true (optionally x_source:'arc:Default' etc. if they use a non-Chrome browser).",
599
653
  });
600
654
  }