@sprid/scout 0.1.3 → 0.1.5
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/CHANGELOG.md +9 -0
- package/package.json +4 -4
- package/src/chrome.js +14 -0
- package/src/config.js +23 -7
- package/src/quick.js +4 -0
- package/src/register.js +10 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.5 - 2026-11-01
|
|
4
|
+
|
|
5
|
+
- Updated dependencies: the MCP SDK 1.32, playwright-core 1.64 and Zod 4.6.7.
|
|
6
|
+
|
|
7
|
+
## 0.1.4 - 2026-10-30
|
|
8
|
+
|
|
9
|
+
- Runs on Windows and Linux: finds Chrome under Program Files and LocalAppData (or the usual Linux paths), and stops a leftover research profile without `pkill`.
|
|
10
|
+
- `sprid-scout-quick` says it needs macOS instead of failing on a missing `osascript`.
|
|
11
|
+
|
|
3
12
|
## 0.1.3 - 2026-10-25
|
|
4
13
|
|
|
5
14
|
- Update the Zod dependency to version 4.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sprid/scout",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Local MCP server that researches a niche over your own Chrome: the accounts winning it, and the ads running in it.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"homepage": "https://sprid.studio/agents",
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"node": ">=20"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
27
|
-
"playwright-core": "^1.
|
|
28
|
-
"zod": "^4.6.
|
|
26
|
+
"@modelcontextprotocol/sdk": "^1.32.2",
|
|
27
|
+
"playwright-core": "^1.64.1",
|
|
28
|
+
"zod": "^4.6.7"
|
|
29
29
|
},
|
|
30
30
|
"publishConfig": {
|
|
31
31
|
"access": "public"
|
package/src/chrome.js
CHANGED
|
@@ -225,6 +225,20 @@ function trackFeedRequests(page, pending) {
|
|
|
225
225
|
|
|
226
226
|
async function killChrome(profileDir) {
|
|
227
227
|
const pattern = `user-data-dir=${profileDir}`;
|
|
228
|
+
if (process.platform === "win32") {
|
|
229
|
+
// No pkill: match the profile on the command line through CIM. The pattern
|
|
230
|
+
// travels in the environment, so a path is never parsed as PowerShell.
|
|
231
|
+
await run("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command",
|
|
232
|
+
"Get-CimInstance Win32_Process -Filter \"Name='chrome.exe'\" | Where-Object { $_.CommandLine -and $_.CommandLine.Contains($env:SCOUT_PROFILE_PATTERN) } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }"],
|
|
233
|
+
{ env: { ...process.env, SCOUT_PROFILE_PATTERN: pattern }, windowsHide: true }).catch(() => {});
|
|
234
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
235
|
+
for (const lock of ["lockfile", "SingletonLock"]) {
|
|
236
|
+
try {
|
|
237
|
+
fs.unlinkSync(path.join(profileDir, lock));
|
|
238
|
+
} catch {}
|
|
239
|
+
}
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
228
242
|
await run("pkill", ["-9", "-f", pattern]).catch(() => {});
|
|
229
243
|
for (let attempt = 0; attempt < 20; attempt++) {
|
|
230
244
|
const alive = await run("pgrep", ["-f", pattern]).then(
|
package/src/config.js
CHANGED
|
@@ -24,12 +24,27 @@ function ensureDirs() {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
function chromeCandidates(platform = process.platform, env = process.env) {
|
|
28
|
+
if (platform === "win32") {
|
|
29
|
+
// Chrome installs per machine under Program Files, or per user under
|
|
30
|
+
// LocalAppData when the person had no admin rights.
|
|
31
|
+
const roots = [env.PROGRAMFILES, env["PROGRAMFILES(X86)"], env.LOCALAPPDATA].filter(Boolean);
|
|
32
|
+
return roots.flatMap((root) => [
|
|
33
|
+
path.win32.join(root, "Google", "Chrome", "Application", "chrome.exe"),
|
|
34
|
+
path.win32.join(root, "Google", "Chrome Beta", "Application", "chrome.exe"),
|
|
35
|
+
path.win32.join(root, "Google", "Chrome SxS", "Application", "chrome.exe"),
|
|
36
|
+
]);
|
|
37
|
+
}
|
|
38
|
+
if (platform === "linux") {
|
|
39
|
+
return ["/usr/bin/google-chrome", "/usr/bin/google-chrome-stable", "/opt/google/chrome/chrome", "/usr/bin/google-chrome-beta"];
|
|
40
|
+
}
|
|
41
|
+
return [
|
|
42
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
43
|
+
`${os.homedir()}/Applications/Google Chrome.app/Contents/MacOS/Google Chrome`,
|
|
44
|
+
"/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta",
|
|
45
|
+
"/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary",
|
|
46
|
+
];
|
|
47
|
+
}
|
|
33
48
|
|
|
34
49
|
class ChromeMissingError extends Error {
|
|
35
50
|
constructor() {
|
|
@@ -43,7 +58,7 @@ class ChromeMissingError extends Error {
|
|
|
43
58
|
let resolvedChrome = null;
|
|
44
59
|
function chromeBinary() {
|
|
45
60
|
if (resolvedChrome) return resolvedChrome;
|
|
46
|
-
const found =
|
|
61
|
+
const found = chromeCandidates().find((candidate) => {
|
|
47
62
|
try {
|
|
48
63
|
fs.accessSync(candidate, fs.constants.X_OK);
|
|
49
64
|
return true;
|
|
@@ -70,6 +85,7 @@ const BROWSER_UA =
|
|
|
70
85
|
|
|
71
86
|
module.exports = {
|
|
72
87
|
NAME,
|
|
88
|
+
chromeCandidates,
|
|
73
89
|
ROOT,
|
|
74
90
|
PROFILE_DIR,
|
|
75
91
|
RUNS_DIR,
|
package/src/quick.js
CHANGED
|
@@ -287,6 +287,10 @@ async function captureWall(urls, { at = 0, outDir, cols = 4 } = {}) {
|
|
|
287
287
|
module.exports = { collect, captureFrames, captureWall, targetUrl, NOT_ENABLED };
|
|
288
288
|
|
|
289
289
|
if (require.main === module) {
|
|
290
|
+
if (process.platform !== "darwin") {
|
|
291
|
+
console.error("sprid-scout-quick drives Chrome through Apple Events, so it runs on macOS only. Use the scout MCP tools instead: they work on every platform.");
|
|
292
|
+
process.exit(1);
|
|
293
|
+
}
|
|
290
294
|
const [target, ...rest] = process.argv.slice(2);
|
|
291
295
|
if (!target) {
|
|
292
296
|
console.error("Usage: sprid-scout-quick <@handle | #hashtag | post-url> [--rounds 10] [--links-only] [--at 0,1,2,5,10]\n sprid-scout-quick wall <post-url> <post-url> ... [--at-second 0]");
|
package/src/register.js
CHANGED
|
@@ -12,12 +12,20 @@ const { NAME } = require("./config");
|
|
|
12
12
|
const SERVER = path.join(__dirname, "server.js");
|
|
13
13
|
const ADD = ["mcp", "add", "--transport", "stdio", "--scope", "user", NAME, "--", process.execPath, SERVER];
|
|
14
14
|
|
|
15
|
+
// Windows installs `claude` through npm as a shim (`claude.cmd`) that only
|
|
16
|
+
// cmd.exe starts, and Node's own path lives under "Program Files".
|
|
17
|
+
function claude(args, options) {
|
|
18
|
+
if (process.platform !== "win32") return execFileSync("claude", args, options);
|
|
19
|
+
const line = ["claude", ...args].map((arg) => (/^[\w@+=:,./\\-]+$/.test(arg) ? arg : `"${arg}"`)).join(" ");
|
|
20
|
+
return execFileSync(line, [], { ...options, shell: true, windowsHide: true });
|
|
21
|
+
}
|
|
22
|
+
|
|
15
23
|
try {
|
|
16
|
-
|
|
24
|
+
claude(["mcp", "remove", "--scope", "user", NAME], { stdio: "ignore" });
|
|
17
25
|
} catch {}
|
|
18
26
|
|
|
19
27
|
try {
|
|
20
|
-
const output =
|
|
28
|
+
const output = claude(ADD, { encoding: "utf8" });
|
|
21
29
|
console.log(`- Claude Code: ${output.trim() || "registered"}`);
|
|
22
30
|
} catch {
|
|
23
31
|
console.log("- Claude Code: could not run `claude mcp add`. Register it by hand with:");
|