The agent-first social media planner: an AI agent drafts and schedules posts across Instagram, Facebook, LinkedIn, YouTube, X, Telegram, Discord, Mastodon, Nostr, WordPress, Ghost, and more, behind a human approval gate you control. Free, open source (MIT), local-first, MCP-native.
Drift inferred · capture-to-capture
No drift recorded — single capability capture; advisories appear once its surface changes.
No tools enumerated yet for this server.
analyzed commit 4848ee8 · analyzer v33 · 1w ago
skills & prompt files 1
- agent-rules pendpost-pendpost-4848ee8/AGENTS.md
danger signals17
- suspicious endpoint t.me pendpost-pendpost-4848ee8/app/src/components/__tests__/comments-panel.test.jsx :68
{ kind: 'comment', commentId: 'c-1', author: 'mock_reader', text: 'Great post!', ts: new Date(now).toISOString(), permalink: 'https://t.me/x/1' }, - suspicious endpoint discord.com pendpost-pendpost-4848ee8/app/src/components/__tests__/setup.test.jsx :841
await user.type(webhookField, 'https://discord.com/api/webhooks/1/abc'); - suspicious endpoint t.me pendpost-pendpost-4848ee8/lib/accounts.mjs :179
telegram: tgChannel.startsWith('@') ? `https://t.me/${tgChannel.slice(1)}` : null, - suspicious endpoint api.telegram.org pendpost-pendpost-4848ee8/lib/comments.mjs :482
const url = `https://api.telegram.org/bot${token}/getUpdates?allowed_updates=["message"]&limit=100`; - suspicious endpoint t.me pendpost-pendpost-4848ee8/lib/drivers/mock-driver.mjs :689
if (p === 'telegram') return `https://t.me/mockchannel/${post.tgMessageId}`; - suspicious endpoint t.me pendpost-pendpost-4848ee8/lib/playbooks.mjs :270
portalUrl: 'https://t.me/BotFather', - suspicious endpoint api.telegram.org pendpost-pendpost-4848ee8/scripts/telegram-social.mjs :88
const apiBase = () => `https://api.telegram.org/bot${readEnv('TELEGRAM_BOT_TOKEN')}`; - suspicious endpoint t.me pendpost-pendpost-4848ee8/scripts/telegram-social.mjs :208
if (ch.startsWith('@')) return `https://t.me/${ch.slice(1)}/${post.tgMessageId}`; - suspicious endpoint discord.com pendpost-pendpost-4848ee8/test/cloud-vault-lanes.test.mjs :33
const DC_URL = `https://discord.com/api/webhooks/${DC_ID}/fake-DISCORD-webhook-secret`; - suspicious endpoint t.me pendpost-pendpost-4848ee8/test/mark-posted-lane.test.mjs :98
const whole = await markPosted({ campaign: 'lane-camp', postId: 'single-1', actor: 'owner', externalUrl: 'https://t.me/c/1' }); - suspicious endpoint discord.com pendpost-pendpost-4848ee8/test/platform-validate-lanes.test.mjs :126
'DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/1/sentinel', - credential in logs credential in log pendpost-pendpost-4848ee8/scripts/gbp-social.mjs :250
console.log(`[ok] Token refreshed ${tokenTail(data.access_token)}, expires ${new Date(Number(vars.GBP_TOKEN_EXPIRES_AT)).toLocaleString('en-US')}.`); - credential in logs credential in log pendpost-pendpost-4848ee8/scripts/linkedin-social.mjs :170
console.log(`[ok] Token refreshed ${tokenTail(data.access_token)}, expires ${new Date(Number(vars.LINKEDIN_TOKEN_EXPIRES_AT)).toLocaleString('en-US')}.`); - credential in logs credential in log pendpost-pendpost-4848ee8/scripts/pinterest-social.mjs :239
console.log(`[ok] Token refreshed ${tokenTail(data.access_token)}, expires ${new Date(Number(vars.PINTEREST_TOKEN_EXPIRES_AT)).toLocaleString('en-US')}.`); - credential in logs credential in log pendpost-pendpost-4848ee8/scripts/tiktok-social.mjs :549
console.log(`\n[ok] Access token stored (${tokenTail(vars.TIKTOK_ACCESS_TOKEN)}).`); - credential in logs credential in log pendpost-pendpost-4848ee8/scripts/x-social.mjs :240
console.log(`[ok] Token refreshed ${tokenTail(data.access_token)}, expires ${new Date(Number(vars.X_TOKEN_EXPIRES_AT)).toLocaleString('en-US')}.`); - credential in logs credential in log pendpost-pendpost-4848ee8/scripts/yt-social.mjs :519
console.log(`\n[ok] Refresh token stored (${tokenTail(data.refresh_token)}).`);
code files: 711
filesystem 231
- fs (weak) pendpost-pendpost-4848ee8/app/src/__tests__/activity-action-coverage.test.js :2
import fs from 'node:fs'; - fs (weak) pendpost-pendpost-4848ee8/app/src/__tests__/contrast.test.js :2
import fs from 'node:fs'; - fs (weak) pendpost-pendpost-4848ee8/app/src/__tests__/eyebrow-sentence-case.test.js :2
import fs from 'node:fs'; - fs (weak) pendpost-pendpost-4848ee8/app/src/__tests__/locale-completeness.test.js :2
import fs from 'node:fs'; - fs (weak) pendpost-pendpost-4848ee8/app/src/__tests__/no-hardcoded-strings.test.js :2
import fs from 'node:fs'; - fs (weak) pendpost-pendpost-4848ee8/app/src/__tests__/self-hosted-fonts.test.js :2
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/bin/pendpost.mjs :7
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/accounts.mjs :3
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/agent-runner.mjs :16
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/assets.mjs :4
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/clients.mjs :15
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/cloud-client.mjs :20
import fs from 'node:fs';
show 28 more
- fs pendpost-pendpost-4848ee8/lib/cloud-config.mjs :22
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/config.mjs :15
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/context.mjs :12
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/covers.mjs :15
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/dashboard.mjs :7
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/drivers/interface.mjs :101
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/drivers/mock-driver.mjs :11
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/lint.mjs :20
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/media.mjs :6
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/mode.mjs :9
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/multi-client.mjs :11
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/notify.mjs :10
import { existsSync } from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/planWrite.mjs :9
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/plans.mjs :4
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/radar-sweep.mjs :16
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/review-ingest.mjs :13
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/review-server.mjs :26
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/reviewers.mjs :22
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/scheduler.mjs :11
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/state.mjs :8
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/static.mjs :2
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/util.mjs :2
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/lib/writes.mjs :10
import fs from 'node:fs'; - fs pendpost-pendpost-4848ee8/packaging/desktop/build-bundle.mjs :28
import fs from 'node:fs'; - fs (weak) pendpost-pendpost-4848ee8/scripts/bluesky-social.mjs :25
import fs from 'node:fs'; - fs (weak) pendpost-pendpost-4848ee8/scripts/check-encoding.mjs :23
import fs from 'node:fs'; - fs (weak) pendpost-pendpost-4848ee8/scripts/dashboard-build.mjs :11
import fs from 'node:fs'; - fs (weak) pendpost-pendpost-4848ee8/scripts/desktop-start.mjs :16
import fs from 'node:fs';
191 more not shown — this panel samples each group; the count above is the real total.
shell / exec 74
- shell pendpost-pendpost-4848ee8/bin/pendpost.mjs :6
import { spawnSync } from 'node:child_process'; - shell pendpost-pendpost-4848ee8/lib/agent-runner.mjs :15
import { spawn } from 'node:child_process'; - shell pendpost-pendpost-4848ee8/lib/api.mjs :8
import { execFile, spawn } from 'node:child_process'; - shell pendpost-pendpost-4848ee8/lib/assets.mjs :7
import { execFile } from 'node:child_process'; - shell pendpost-pendpost-4848ee8/lib/cli-client.mjs :37
import { spawnSync } from 'node:child_process'; - shell pendpost-pendpost-4848ee8/lib/covers.mjs :17
import { execFile } from 'node:child_process'; - shell pendpost-pendpost-4848ee8/lib/notify.mjs :9
import { execFile } from 'node:child_process'; - shell pendpost-pendpost-4848ee8/lib/radar-sweep.mjs :479
// { skipped:'budget' } report, never a silent spawn (the job row counts toward - shell pendpost-pendpost-4848ee8/lib/radar.mjs :36
import { execFile } from 'node:child_process'; - shell pendpost-pendpost-4848ee8/lib/scheduler.mjs :13
import { execFile } from 'node:child_process'; - shell pendpost-pendpost-4848ee8/lib/util.mjs :306
// Homebrew, so a bare execFile('ffprobe') dies with spawn ENOENT under the - shell pendpost-pendpost-4848ee8/lib/verify.mjs :12
import { execFile } from 'node:child_process';
show 28 more
- shell pendpost-pendpost-4848ee8/lib/writes.mjs :13
import { execFile } from 'node:child_process'; - shell pendpost-pendpost-4848ee8/mcpb/server/index.mjs :5
import { spawn } from 'node:child_process'; - shell pendpost-pendpost-4848ee8/packaging/desktop/build-bundle.mjs :31
import { spawnSync } from 'node:child_process'; - shell (weak) pendpost-pendpost-4848ee8/scripts/check-encoding.mjs :22
import { execFileSync } from 'node:child_process'; - shell (weak) pendpost-pendpost-4848ee8/scripts/dashboard-build.mjs :13
import { spawn, execFileSync } from 'node:child_process'; - shell (weak) pendpost-pendpost-4848ee8/scripts/gbp-social.mjs :78
import { execFile } from 'node:child_process'; - shell (weak) pendpost-pendpost-4848ee8/scripts/linkedin-social.mjs :39
import { execFile } from 'node:child_process'; - shell (weak) pendpost-pendpost-4848ee8/scripts/pinterest-social.mjs :68
import { execFile } from 'node:child_process'; - shell (weak) pendpost-pendpost-4848ee8/scripts/tiktok-social.mjs :70
import { execFile } from 'node:child_process'; - shell (weak) pendpost-pendpost-4848ee8/scripts/x-social.mjs :63
import { execFile } from 'node:child_process'; - shell (weak) pendpost-pendpost-4848ee8/scripts/yt-social.mjs :38
import { execFile } from 'node:child_process'; - shell pendpost-pendpost-4848ee8/server.mjs :18
import { execFile } from 'node:child_process'; - shell (weak) pendpost-pendpost-4848ee8/test/agent-runner.test.mjs :320
ok(tiny.lanes.length === 5 && tiny.lanes.every((l) => l.length === 1), 'one query: five lanes still isolate one-per-spawn (unchanged)'); - shell (weak) pendpost-pendpost-4848ee8/test/alt-text.test.mjs :34
import { execFile } from 'node:child_process'; - shell (weak) pendpost-pendpost-4848ee8/test/avsync-backstop.test.mjs :53
import { execFileSync } from 'node:child_process'; - shell (weak) pendpost-pendpost-4848ee8/test/boot-start.test.mjs :53
'expected spawnSync("npm", ["run", "build"], ...) to build app/dist on first run', - shell (weak) pendpost-pendpost-4848ee8/test/cli-client-target.test.mjs :22
import { spawnSync } from 'node:child_process'; - shell (weak) pendpost-pendpost-4848ee8/test/clients-overview.test.mjs :16
import { execFileSync } from 'node:child_process'; - shell (weak) pendpost-pendpost-4848ee8/test/comment-moderation.test.mjs :26
import { execFileSync } from 'node:child_process'; - shell (weak) pendpost-pendpost-4848ee8/test/comment-reply-gate.test.mjs :23
import { execFileSync } from 'node:child_process'; - shell (weak) pendpost-pendpost-4848ee8/test/comments-reply.test.mjs :18
import { execFileSync } from 'node:child_process'; - shell (weak) pendpost-pendpost-4848ee8/test/concurrency.test.mjs :19
import { execFile } from 'node:child_process'; - shell (weak) pendpost-pendpost-4848ee8/test/connect-discover.test.mjs :22
import { execFileSync } from 'node:child_process'; - shell (weak) pendpost-pendpost-4848ee8/test/dashboard-gitcheck.test.mjs :10
import { execFileSync } from 'node:child_process'; - shell (weak) pendpost-pendpost-4848ee8/test/demographics.test.mjs :32
import { execFileSync } from 'node:child_process'; - shell (weak) pendpost-pendpost-4848ee8/test/disclosure-settings.test.mjs :37
import { execFile } from 'node:child_process'; - shell (weak) pendpost-pendpost-4848ee8/test/discord-structured.test.mjs :61
import { execFile } from 'node:child_process'; - shell (weak) pendpost-pendpost-4848ee8/test/draft-handoff.test.mjs :40
import { execFile } from 'node:child_process';
34 more not shown — this panel samples each group; the count above is the real total.
network 72
- net pendpost-pendpost-4848ee8/app/src/components/Composer.jsx :1575
fetch(chosen.srtUrl) - net pendpost-pendpost-4848ee8/app/src/components/Setup.jsx :172
// (meta/telegram/tiktok/mastodon/ghost/nostr) never fetch (the server would 200 with - net pendpost-pendpost-4848ee8/app/src/components/UpdateToast.jsx :10
try { await fetch('/api/dashboard-update', { method: 'POST' }); } catch { /* poll stays source of truth */ } - net (weak) pendpost-pendpost-4848ee8/app/src/components/__tests__/insights-fetch-button.test.jsx :10
// after a recent fetch (so the owner sees it succeeded and need not refetch), - net (weak) pendpost-pendpost-4848ee8/app/src/components/__tests__/setup.test.jsx :47
// controls render off the immediate fetch (no timer advance). Overridden per test. - net pendpost-pendpost-4848ee8/app/src/lib/api.js :4
const res = await fetch(path); - net pendpost-pendpost-4848ee8/app/src/lib/cloud.js :14
const res = await fetch(path); - net pendpost-pendpost-4848ee8/app/src/main.jsx :12
// QueryClientProvider so it can read the clients query; before the first fetch (or - net pendpost-pendpost-4848ee8/app/src/review/main.js :76
const res = await fetch(`/review/${TOKEN}/bundle`, { headers: { Accept: 'application/json' } }); - net pendpost-pendpost-4848ee8/bin/pendpost.mjs :146
const res = await fetch(`${URL_BASE}/api/health`); - net pendpost-pendpost-4848ee8/lib/cloud-client.mjs :148
res = await fetch(new URL(urlPath, base), { - net pendpost-pendpost-4848ee8/lib/comments.mjs :317
const res = await fetch(url, { ...init, signal: AbortSignal.timeout(15_000) });
show 28 more
- net pendpost-pendpost-4848ee8/lib/insights.mjs :491
errorMessage: failed ? `${failed} fetch(es) failed: ${failedLanes.join(', ')}` : null, - net pendpost-pendpost-4848ee8/lib/public-media.mjs :104
const res = await fetch(url.trim(), { method: 'HEAD', redirect: 'follow', signal: AbortSignal.timeout(10_000) }); - net pendpost-pendpost-4848ee8/lib/radar-sweep.mjs :346
// A null fetch (mock/offline, or a non-ok HTTP the fetcher degraded) still counts as a - net pendpost-pendpost-4848ee8/lib/radar.mjs :1026
const res = await fetch(url, { ...init, signal: AbortSignal.timeout(15_000) }); - net pendpost-pendpost-4848ee8/lib/review-server.mjs :15
import http from 'node:http'; - net pendpost-pendpost-4848ee8/lib/writes.mjs :1336
// The PUBLIC media URL(s) a post would hand to a platform's server-side fetch (IG feed - net pendpost-pendpost-4848ee8/packaging/desktop/build-bundle.mjs :144
const res = await fetch(url); - net (weak) pendpost-pendpost-4848ee8/scripts/dashboard-build.mjs :114
// Refresh the update status: fetch (unless throttled off), then record how far - net (weak) pendpost-pendpost-4848ee8/scripts/discord-social.mjs :94
const res = await fetch(url, init); - net (weak) pendpost-pendpost-4848ee8/scripts/gbp-social.mjs :76
import http from 'node:http'; - net (weak) pendpost-pendpost-4848ee8/scripts/ghost-social.mjs :188
const res = await fetch(url, init); - net (weak) pendpost-pendpost-4848ee8/scripts/linkedin-social.mjs :37
import http from 'node:http'; - net (weak) pendpost-pendpost-4848ee8/scripts/mastodon-social.mjs :164
res = await fetch(url, { ...init, signal: ctrl.signal }); - net (weak) pendpost-pendpost-4848ee8/scripts/meta-social.mjs :143
const res = await fetch(url, { method, body }); - net (weak) pendpost-pendpost-4848ee8/scripts/nostr-social.mjs :709
const discovery = await fetch(`${base}/.well-known/nostr/nip96.json`, { headers: { Accept: 'application/json' } }); - net (weak) pendpost-pendpost-4848ee8/scripts/pinterest-social.mjs :66
import http from 'node:http'; - net (weak) pendpost-pendpost-4848ee8/scripts/reddit-social.mjs :132
const res = await fetch('https://www.reddit.com/api/v1/access_token', { - net (weak) pendpost-pendpost-4848ee8/scripts/telegram-social.mjs :98
const res = await fetch(url, init); - net (weak) pendpost-pendpost-4848ee8/scripts/tiktok-social.mjs :68
import http from 'node:http'; - net (weak) pendpost-pendpost-4848ee8/scripts/wordpress-social.mjs :186
const res = await fetch(url, init); - net (weak) pendpost-pendpost-4848ee8/scripts/x-social.mjs :61
import http from 'node:http'; - net (weak) pendpost-pendpost-4848ee8/scripts/yt-social.mjs :36
import http from 'node:http'; - net pendpost-pendpost-4848ee8/server.mjs :17
import http from 'node:http'; - net (weak) pendpost-pendpost-4848ee8/test/agent-adopt.test.mjs :14
import http from 'node:http'; - net (weak) pendpost-pendpost-4848ee8/test/alt-text.test.mjs :33
import http from 'node:http'; - net (weak) pendpost-pendpost-4848ee8/test/disclosure-settings.test.mjs :36
import http from 'node:http'; - net (weak) pendpost-pendpost-4848ee8/test/discord-structured.test.mjs :60
import http from 'node:http'; - net (weak) pendpost-pendpost-4848ee8/test/draft-handoff.test.mjs :39
import http from 'node:http';
32 more not shown — this panel samples each group; the count above is the real total.
secrets 3
- secrets pendpost-pendpost-4848ee8/lib/flags.mjs :32
const t = String(process.env.PENDPOST_AUTH_TOKEN || '').trim(); - secrets (weak) pendpost-pendpost-4848ee8/test/agent-runner.test.mjs :68
process.stderr.write('boom: token ' + process.env.CLAUDE_CODE_OAUTH_TOKEN + ' was rejected\\n'); - secrets (weak) pendpost-pendpost-4848ee8/test/auth-gate.test.mjs :19
const savedToken = process.env.PENDPOST_AUTH_TOKEN;
install hooks 1
- prepack pendpost-pendpost-4848ee8/package.json :65
npm run build
obfuscation 3
- dynamic require()/import() pendpost-pendpost-4848ee8/test/concurrency.test.mjs :44
const { mutatePlan } = await import(${JSON.stringify(planWriteUrl)}); - dynamic require()/import() pendpost-pendpost-4848ee8/test/nostr-longform.test.mjs :149
await import(${JSON.stringify(NOSTR_SCRIPT)}); - dynamic require()/import() pendpost-pendpost-4848ee8/test/richer-analytics.test.mjs :163
await import(${JSON.stringify(NOSTR_SCRIPT)});
perm:untrusted 1
- untrusted (weak) pendpost-pendpost-4848ee8/test/integration/sandbox.mjs :181
const setupState = await (await fetch(`${base}/authentication/setup/`)).json();