@m13v/s4l 1.6.197-rc.7
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/README.md +143 -0
- package/SKILL.md +342 -0
- package/bin/cli.js +980 -0
- package/bin/cookie-helper.js +315 -0
- package/bin/platform.js +59 -0
- package/bin/scheduler/index.js +12 -0
- package/bin/scheduler/launchd.js +518 -0
- package/browser-agent-configs/all-agents-mcp.json +68 -0
- package/browser-agent-configs/linkedin-agent-mcp.json +16 -0
- package/browser-agent-configs/linkedin-agent.json +17 -0
- package/browser-agent-configs/linkedin-harness-mcp.json +21 -0
- package/browser-agent-configs/reddit-agent-mcp.json +16 -0
- package/browser-agent-configs/reddit-agent.json +17 -0
- package/browser-agent-configs/twitter-harness-mcp.json +18 -0
- package/config.example.json +45 -0
- package/mcp/dist/index.js +4212 -0
- package/mcp/dist/onboarding.js +200 -0
- package/mcp/dist/panel.html +176 -0
- package/mcp/dist/product-link.html +102 -0
- package/mcp/dist/repo.js +222 -0
- package/mcp/dist/runtime.js +1079 -0
- package/mcp/dist/screencast.js +323 -0
- package/mcp/dist/setup.js +545 -0
- package/mcp/dist/telemetry.js +306 -0
- package/mcp/dist/twitterAuth.js +138 -0
- package/mcp/dist/version.js +271 -0
- package/mcp/dist/version.json +4 -0
- package/mcp/install-runtime.mjs +70 -0
- package/mcp/install.mjs +169 -0
- package/mcp/manifest.json +80 -0
- package/mcp/menubar/dashboard_server.py +213 -0
- package/mcp/menubar/s4l_card.py +1314 -0
- package/mcp/menubar/s4l_log_relay.py +179 -0
- package/mcp/menubar/s4l_menubar.py +2439 -0
- package/mcp/menubar/s4l_state.py +891 -0
- package/mcp/package.json +34 -0
- package/mcp/shared/doctor.cjs +437 -0
- package/mcp/shared/onboarding-ledger.cjs +324 -0
- package/mcp-servers/browser-harness/server.py +968 -0
- package/package.json +160 -0
- package/requirements.txt +20 -0
- package/scripts/_compute_allowlist.py +58 -0
- package/scripts/_db_update.py +20 -0
- package/scripts/_filt.py +9 -0
- package/scripts/_li_notif_match.py +76 -0
- package/scripts/_li_notif_orchestrate.py +126 -0
- package/scripts/_lock_preempt_test.py +60 -0
- package/scripts/_run_icp_precheck.py +57 -0
- package/scripts/a16z_pearx_calendar_reminders.py +99 -0
- package/scripts/account_resolver.py +141 -0
- package/scripts/active_campaigns.py +114 -0
- package/scripts/active_users.py +190 -0
- package/scripts/amplitude_24h_signups.py +468 -0
- package/scripts/amplitude_signups.py +177 -0
- package/scripts/apply_onboarding_selections.py +131 -0
- package/scripts/audience_pages.py +243 -0
- package/scripts/audit_helper.py +120 -0
- package/scripts/author_history_block.py +353 -0
- package/scripts/autopilot_stall_watch.py +284 -0
- package/scripts/backfill_twitter_attempts_topic.py +81 -0
- package/scripts/backfill_twitter_log_post_no_id.py +322 -0
- package/scripts/bench_dashboard.sh +138 -0
- package/scripts/bh_send.py +39 -0
- package/scripts/build_persona.py +409 -0
- package/scripts/bulk_icp.py +18 -0
- package/scripts/campaign_bump.py +51 -0
- package/scripts/capture_thread_media.py +288 -0
- package/scripts/check_browser_lock_health.sh +81 -0
- package/scripts/check_external_pool_depth.py +253 -0
- package/scripts/check_unread_web_chats.py +28 -0
- package/scripts/claim_web_chat.py +47 -0
- package/scripts/classify_run_error.py +158 -0
- package/scripts/claude_job.py +988 -0
- package/scripts/clean_stale_singleton.sh +56 -0
- package/scripts/cleanup_harness_tabs.py +68 -0
- package/scripts/copy_browser_cookies.py +454 -0
- package/scripts/counterparty_history.py +350 -0
- package/scripts/db.py +57 -0
- package/scripts/discover_claude_profiles.py +120 -0
- package/scripts/discover_linkedin_candidates.py +984 -0
- package/scripts/dm_conversation.py +682 -0
- package/scripts/dm_db_update.py +69 -0
- package/scripts/dm_engage_helper.py +161 -0
- package/scripts/dm_outreach_helper.py +147 -0
- package/scripts/dm_outreach_twitter_helper.py +129 -0
- package/scripts/dm_send_log.py +106 -0
- package/scripts/dm_short_links.py +1084 -0
- package/scripts/dump_web_chat_history.py +47 -0
- package/scripts/engage_github.py +640 -0
- package/scripts/engage_reddit.py +1235 -0
- package/scripts/engage_twitter_helper.py +301 -0
- package/scripts/engagement_styles.py +1787 -0
- package/scripts/enrich_twitter_candidates.py +82 -0
- package/scripts/feedback_digest.py +448 -0
- package/scripts/fetch_prospect_profile.py +312 -0
- package/scripts/fetch_twitter_t1.py +134 -0
- package/scripts/find_threads.py +530 -0
- package/scripts/follow_gate_log.py +59 -0
- package/scripts/funnel_per_day.py +194 -0
- package/scripts/generate_daily_human_style.py +494 -0
- package/scripts/generation_trace.py +173 -0
- package/scripts/get_run_cost.py +107 -0
- package/scripts/github_engage_helper.py +93 -0
- package/scripts/github_tools.py +509 -0
- package/scripts/harness_overlay.py +556 -0
- package/scripts/harvest_twitter_following.py +243 -0
- package/scripts/heartbeat.sh +70 -0
- package/scripts/history_context.py +284 -0
- package/scripts/http_api.py +206 -0
- package/scripts/human_dm_replies_helper.py +169 -0
- package/scripts/identity.py +302 -0
- package/scripts/ig_batch_creator.sh +93 -0
- package/scripts/ig_post_type_picker.py +243 -0
- package/scripts/ig_scrape_transcribe.sh +91 -0
- package/scripts/ingest_human_dm_replies.py +271 -0
- package/scripts/ingest_web_chat_replies.py +229 -0
- package/scripts/install_fleet.py +187 -0
- package/scripts/invent_mcp_server.py +350 -0
- package/scripts/invent_topics.py +1462 -0
- package/scripts/learned_preferences.py +263 -0
- package/scripts/li_discovery.py +161 -0
- package/scripts/link_edit_helper.py +142 -0
- package/scripts/link_tail.py +592 -0
- package/scripts/linkedin_api.py +561 -0
- package/scripts/linkedin_browser.py +730 -0
- package/scripts/linkedin_cooldown.py +128 -0
- package/scripts/linkedin_exclusions.py +234 -0
- package/scripts/linkedin_killswitch.py +1333 -0
- package/scripts/linkedin_search_topic_schema.py +49 -0
- package/scripts/linkedin_unipile.py +658 -0
- package/scripts/linkedin_url.py +228 -0
- package/scripts/log_claude_session.py +636 -0
- package/scripts/log_draft.py +143 -0
- package/scripts/log_linkedin_search_attempts.py +126 -0
- package/scripts/log_post.py +651 -0
- package/scripts/log_run.py +364 -0
- package/scripts/log_thread_media.py +108 -0
- package/scripts/log_twitter_search_attempts.py +150 -0
- package/scripts/log_twitter_skips.py +211 -0
- package/scripts/lookup_post.py +78 -0
- package/scripts/mark_web_chat_processed.py +32 -0
- package/scripts/mcp_lock_proxy.py +370 -0
- package/scripts/memory_snapshot.py +972 -0
- package/scripts/merge_review_queue.py +215 -0
- package/scripts/mint_external_pool.py +182 -0
- package/scripts/mint_kent_pool.py +249 -0
- package/scripts/moltbook_post.py +320 -0
- package/scripts/moltbook_tools.py +159 -0
- package/scripts/pending_threads.py +188 -0
- package/scripts/pick_ig_account.py +177 -0
- package/scripts/pick_project.py +208 -0
- package/scripts/pick_search_topic.py +771 -0
- package/scripts/pick_thread_target.py +279 -0
- package/scripts/pick_twitter_thread_target.py +202 -0
- package/scripts/podlog_fetch_batch.sh +32 -0
- package/scripts/post_github.py +1311 -0
- package/scripts/post_reddit.py +2668 -0
- package/scripts/precompute_dashboard_stats.py +204 -0
- package/scripts/preflight.sh +297 -0
- package/scripts/progress.py +88 -0
- package/scripts/project_excludes.py +353 -0
- package/scripts/project_slugs.py +91 -0
- package/scripts/project_stats.py +241 -0
- package/scripts/project_stats_json.py +1563 -0
- package/scripts/project_topics.py +192 -0
- package/scripts/qualified_query_bank.py +436 -0
- package/scripts/reap_stale_claude_sessions.py +867 -0
- package/scripts/reddit_browser.py +2549 -0
- package/scripts/reddit_browser_fetch.py +141 -0
- package/scripts/reddit_browser_lock.py +593 -0
- package/scripts/reddit_chat_sync.py +710 -0
- package/scripts/reddit_query_bank.py +200 -0
- package/scripts/reddit_threads_helper.py +151 -0
- package/scripts/reddit_tools.py +956 -0
- package/scripts/refresh_instagram_tokens.py +280 -0
- package/scripts/release-mcpb.sh +497 -0
- package/scripts/reply_db.py +334 -0
- package/scripts/reply_insert.py +98 -0
- package/scripts/reply_risk_digest.py +761 -0
- package/scripts/reset-test-machine.sh +602 -0
- package/scripts/restore_twitter_session.py +177 -0
- package/scripts/ripen_reddit_plan.py +478 -0
- package/scripts/run_claude.sh +433 -0
- package/scripts/run_moltbook_cycle.py +555 -0
- package/scripts/s4l_box_update.sh +226 -0
- package/scripts/s4l_channel.py +103 -0
- package/scripts/s4l_ctl.sh +75 -0
- package/scripts/s4l_env.py +47 -0
- package/scripts/saps_activity.py +126 -0
- package/scripts/saps_mode.py +328 -0
- package/scripts/scan_dm_candidates.py +580 -0
- package/scripts/scan_github_replies.py +168 -0
- package/scripts/scan_instagram_comments.py +481 -0
- package/scripts/scan_moltbook_replies.py +252 -0
- package/scripts/scan_pii.py +190 -0
- package/scripts/scan_reddit_replies.py +377 -0
- package/scripts/scan_twitter_mentions_browser.py +327 -0
- package/scripts/scan_twitter_thread_followups.py +299 -0
- package/scripts/scan_x_profile.py +384 -0
- package/scripts/schedule_state.py +202 -0
- package/scripts/scheduled_tasks_snapshot.py +123 -0
- package/scripts/score_linkedin_candidates.py +419 -0
- package/scripts/score_twitter_candidates.py +718 -0
- package/scripts/scrape_linkedin_comment_stats.py +1755 -0
- package/scripts/scrape_linkedin_stats_browser.py +52 -0
- package/scripts/scrape_reddit_views.py +365 -0
- package/scripts/seed_search_queries.py +453 -0
- package/scripts/seed_search_topics.py +127 -0
- package/scripts/send_web_chat_reply.py +130 -0
- package/scripts/sentry_init.py +128 -0
- package/scripts/setup_twitter_auth.py +1320 -0
- package/scripts/snapshot.py +583 -0
- package/scripts/stats.py +2702 -0
- package/scripts/stats_helper.py +52 -0
- package/scripts/strike_alert.py +783 -0
- package/scripts/sweep_post_link_clicks.py +107 -0
- package/scripts/sync_ig_to_posts.py +147 -0
- package/scripts/test_browser_lock.py +189 -0
- package/scripts/test_installation_api.sh +52 -0
- package/scripts/test_percard_posting.py +142 -0
- package/scripts/top_dud_linkedin_queries.py +71 -0
- package/scripts/top_dud_reddit_queries.py +67 -0
- package/scripts/top_dud_twitter_queries.py +71 -0
- package/scripts/top_dud_twitter_topics.py +102 -0
- package/scripts/top_linkedin_queries.py +55 -0
- package/scripts/top_omitted_reddit_topics.py +91 -0
- package/scripts/top_performers.py +588 -0
- package/scripts/top_search_topics.py +180 -0
- package/scripts/top_twitter_queries.py +190 -0
- package/scripts/twitter_access_check.py +382 -0
- package/scripts/twitter_account.py +41 -0
- package/scripts/twitter_batch_phase.py +126 -0
- package/scripts/twitter_browser.py +2804 -0
- package/scripts/twitter_cookie_mirror.py +130 -0
- package/scripts/twitter_cycle_helper.py +310 -0
- package/scripts/twitter_gen_links.py +287 -0
- package/scripts/twitter_post_plan.py +1188 -0
- package/scripts/twitter_scan.py +324 -0
- package/scripts/twitter_supply_signal.py +57 -0
- package/scripts/twitter_threads_helper.py +152 -0
- package/scripts/unclaim_web_chat.py +29 -0
- package/scripts/update_instagram_stats.py +261 -0
- package/scripts/update_linkedin_stats_from_feed.py +328 -0
- package/scripts/version.py +72 -0
- package/scripts/watchdog_hung_runs.py +343 -0
- package/scripts/write_generation_trace.py +73 -0
- package/setup/SKILL.md +277 -0
- package/skill/amplitude-24h-signups.sh +38 -0
- package/skill/archive-old-logs.sh +40 -0
- package/skill/audit-dm-staleness.sh +42 -0
- package/skill/audit-linkedin.sh +14 -0
- package/skill/audit-moltbook.sh +4 -0
- package/skill/audit-reddit-resurrect.sh +67 -0
- package/skill/audit-reddit.sh +4 -0
- package/skill/audit-twitter.sh +4 -0
- package/skill/audit.sh +287 -0
- package/skill/backfill-twitter-attempts-topic.sh +19 -0
- package/skill/backfill-twitter-ghost-posts.sh +24 -0
- package/skill/check-external-pool-depth.sh +7 -0
- package/skill/check-web-chats.sh +203 -0
- package/skill/dm-outreach-linkedin.sh +250 -0
- package/skill/dm-outreach-reddit.sh +274 -0
- package/skill/dm-outreach-twitter.sh +265 -0
- package/skill/engage-dm-replies-linkedin.sh +4 -0
- package/skill/engage-dm-replies-reddit.sh +4 -0
- package/skill/engage-dm-replies-twitter.sh +4 -0
- package/skill/engage-dm-replies.sh +1597 -0
- package/skill/engage-linkedin.sh +581 -0
- package/skill/engage-moltbook.sh +36 -0
- package/skill/engage-reddit.sh +146 -0
- package/skill/engage-twitter.sh +467 -0
- package/skill/github-engage.sh +176 -0
- package/skill/ingest-web-chat-replies.sh +38 -0
- package/skill/invent-supply-test.sh +100 -0
- package/skill/invent-topics.sh +50 -0
- package/skill/lib/linkedin-backend.sh +364 -0
- package/skill/lib/platform.sh +48 -0
- package/skill/lib/reddit-backend.sh +234 -0
- package/skill/lib/twitter-backend.sh +314 -0
- package/skill/link-edit-github.sh +136 -0
- package/skill/link-edit-moltbook.sh +117 -0
- package/skill/link-edit-reddit.sh +201 -0
- package/skill/linkedin-presence.sh +182 -0
- package/skill/linkedin-recovery.sh +282 -0
- package/skill/lock.sh +647 -0
- package/skill/memory-snapshot.sh +39 -0
- package/skill/precompute-stats.sh +35 -0
- package/skill/prewarm-funnel.sh +104 -0
- package/skill/refresh-instagram-tokens.sh +57 -0
- package/skill/refresh-twitter-following.sh +52 -0
- package/skill/reply-risk-digest.sh +31 -0
- package/skill/run-cycle-update-guard.sh +44 -0
- package/skill/run-draft-and-publish.sh +123 -0
- package/skill/run-generate-daily-style.sh +50 -0
- package/skill/run-github-launchd.sh +62 -0
- package/skill/run-github.sh +102 -0
- package/skill/run-instagram-daily.sh +149 -0
- package/skill/run-instagram-render.sh +875 -0
- package/skill/run-linkedin-launchd.sh +81 -0
- package/skill/run-linkedin-unipile.sh +130 -0
- package/skill/run-linkedin.sh +1593 -0
- package/skill/run-moltbook-launchd.sh +61 -0
- package/skill/run-moltbook.sh +38 -0
- package/skill/run-overlay-watch.sh +100 -0
- package/skill/run-reddit-search-launchd.sh +64 -0
- package/skill/run-reddit-search.sh +505 -0
- package/skill/run-reddit-threads-double.sh +32 -0
- package/skill/run-reddit-threads.sh +847 -0
- package/skill/run-scan-moltbook-replies.sh +57 -0
- package/skill/run-twitter-cycle-launchd.sh +63 -0
- package/skill/run-twitter-cycle-singleton.sh +62 -0
- package/skill/run-twitter-cycle.sh +2408 -0
- package/skill/run-twitter-threads.sh +592 -0
- package/skill/scan-instagram-replies.sh +61 -0
- package/skill/scan-twitter-followups.sh +57 -0
- package/skill/social-autoposter-update.sh +66 -0
- package/skill/stats-instagram.sh +72 -0
- package/skill/stats-linkedin.sh +271 -0
- package/skill/stats-moltbook.sh +4 -0
- package/skill/stats-reddit.sh +4 -0
- package/skill/stats-twitter.sh +4 -0
- package/skill/stats.sh +521 -0
- package/skill/strike-alert.sh +18 -0
- package/skill/styles.sh +87 -0
- package/skill/sweep-link-clicks.sh +40 -0
- package/skill/topics.sh +51 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Claim a web-chat thread (reset unread_by_founder=0, set 5-min cooldown).
|
|
3
|
+
|
|
4
|
+
HTTP-only: POST /api/v1/web-chat/threads/<thread_id>/claim. The cooldown
|
|
5
|
+
prevents multiple Claude sessions from spawning for the same visitor when they
|
|
6
|
+
send rapid-fire messages.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
python3 claim_web_chat.py <thread_id> [--check-only]
|
|
10
|
+
|
|
11
|
+
--check-only: exit 0 if claimable, exit 2 if still in cooldown (no write).
|
|
12
|
+
Without --check-only: claims (sets unread_by_founder=0, claimed_until=now+5min).
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import argparse
|
|
16
|
+
import os
|
|
17
|
+
import sys
|
|
18
|
+
|
|
19
|
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
20
|
+
from http_api import api_post
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def main():
|
|
24
|
+
parser = argparse.ArgumentParser()
|
|
25
|
+
parser.add_argument("thread_id")
|
|
26
|
+
parser.add_argument("--check-only", action="store_true")
|
|
27
|
+
args = parser.parse_args()
|
|
28
|
+
|
|
29
|
+
resp = api_post(
|
|
30
|
+
f"/api/v1/web-chat/threads/{args.thread_id}/claim",
|
|
31
|
+
{"check_only": bool(args.check_only)},
|
|
32
|
+
)
|
|
33
|
+
data = resp.get("data") or {}
|
|
34
|
+
state = data.get("state")
|
|
35
|
+
|
|
36
|
+
if state == "cooldown":
|
|
37
|
+
print(f"thread {args.thread_id} in cooldown until {data.get('claimed_until')}")
|
|
38
|
+
sys.exit(2)
|
|
39
|
+
if state == "claimable":
|
|
40
|
+
print(f"thread {args.thread_id} claimable")
|
|
41
|
+
sys.exit(0)
|
|
42
|
+
# state == "claimed"
|
|
43
|
+
print(f"claimed thread {args.thread_id} (cooldown {data.get('cooldown_min', 5)}m)")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
if __name__ == "__main__":
|
|
47
|
+
main()
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Classify a Claude CLI run envelope or shell log into a single failure reason key.
|
|
3
|
+
|
|
4
|
+
Reads stdin OR a file path, prints ONE snake_case reason key on stdout (or empty
|
|
5
|
+
line if nothing matched). Used by run-twitter-cycle.sh and peer pipelines so
|
|
6
|
+
dashboard "failed: <reason>" pills carry the *actual* error class instead of
|
|
7
|
+
collapsing every Claude-side death to a generic 'phase1_no_tweets'.
|
|
8
|
+
|
|
9
|
+
Patterns ordered most-specific first; the first match wins. Order matters:
|
|
10
|
+
- monthly_limit must beat the generic rate_limit fallback
|
|
11
|
+
- credit_balance must beat the generic api_error fallback
|
|
12
|
+
- stream_idle_timeout must beat the generic api_error fallback
|
|
13
|
+
|
|
14
|
+
Reason keys mirror existing dashboard conventions (`bin/server.js` renders them
|
|
15
|
+
as "failed: <reason>"). Do not rename without sweeping the dashboard's tooltip
|
|
16
|
+
copy.
|
|
17
|
+
|
|
18
|
+
Usage:
|
|
19
|
+
cat run.log | classify_run_error.py
|
|
20
|
+
classify_run_error.py /path/to/log.txt
|
|
21
|
+
classify_run_error.py --quiet # exit 1 if no match (for grep-style chaining)
|
|
22
|
+
"""
|
|
23
|
+
import re
|
|
24
|
+
import sys
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
|
|
27
|
+
# Order: most-specific first. Each entry is (reason_key, list_of_regex_patterns).
|
|
28
|
+
# Patterns are matched case-insensitive against the full text.
|
|
29
|
+
PATTERNS = [
|
|
30
|
+
# Anthropic billing / quota hits. Single source of truth so dashboard
|
|
31
|
+
# tooltip copy stays consistent across every pipeline.
|
|
32
|
+
("monthly_limit", [
|
|
33
|
+
r'"api_error_status":\s*429',
|
|
34
|
+
r"monthly usage limit",
|
|
35
|
+
r"hit your org'?s monthly",
|
|
36
|
+
r"monthly limit reached",
|
|
37
|
+
r"month'?s (?:usage|allowance|cap)",
|
|
38
|
+
r"\"hit your limit\"",
|
|
39
|
+
r"hit your limit",
|
|
40
|
+
]),
|
|
41
|
+
("daily_limit", [
|
|
42
|
+
r"daily rate limit",
|
|
43
|
+
r"daily usage limit",
|
|
44
|
+
r"daily limit reached",
|
|
45
|
+
]),
|
|
46
|
+
("rate_limit_5h", [
|
|
47
|
+
r"5[\s-]?hour (?:rate )?limit",
|
|
48
|
+
r"rate_limit_5h",
|
|
49
|
+
r"per[\s-]?5h (?:rate )?limit",
|
|
50
|
+
]),
|
|
51
|
+
("credit_balance", [
|
|
52
|
+
r"credit balance is too low",
|
|
53
|
+
r"insufficient credit",
|
|
54
|
+
r"out of credits",
|
|
55
|
+
]),
|
|
56
|
+
# Anthropic streaming / transient errors. These are recoverable on retry
|
|
57
|
+
# but burn the whole cycle's spend when they happen, so surface them with
|
|
58
|
+
# a distinct key (operators care about the difference between "we hit the
|
|
59
|
+
# cap" and "Anthropic's stream blinked").
|
|
60
|
+
("stream_idle_timeout", [
|
|
61
|
+
r"stream idle timeout",
|
|
62
|
+
r"partial response received",
|
|
63
|
+
]),
|
|
64
|
+
("api_overloaded", [
|
|
65
|
+
r'"api_error_status":\s*529',
|
|
66
|
+
r"overloaded_error",
|
|
67
|
+
r"\"type\":\s*\"overloaded\"",
|
|
68
|
+
]),
|
|
69
|
+
("api_unavailable", [
|
|
70
|
+
r'"api_error_status":\s*503',
|
|
71
|
+
r"service unavailable",
|
|
72
|
+
]),
|
|
73
|
+
("api_error_500", [
|
|
74
|
+
r'"api_error_status":\s*500',
|
|
75
|
+
r"internal server error",
|
|
76
|
+
]),
|
|
77
|
+
("context_overflow", [
|
|
78
|
+
r"context[\s_-]?length (?:exceeded|too long)",
|
|
79
|
+
r"context[\s_-]?window (?:exceeded|too long)",
|
|
80
|
+
r"prompt is too long",
|
|
81
|
+
r"max(?:imum)? context (?:length|window)",
|
|
82
|
+
]),
|
|
83
|
+
# Claude CLI is not authenticated. On a fresh machine the standalone
|
|
84
|
+
# `claude` CLI that the pipelines shell out to (via run_claude.sh) has its
|
|
85
|
+
# own credential store (~/.claude/.credentials.json / keychain) SEPARATE
|
|
86
|
+
# from Claude Desktop, so it can be logged out even when the MCP host is
|
|
87
|
+
# logged in. The CLI then returns a result envelope with is_error:true and
|
|
88
|
+
# result:"Not logged in · Please run /login". Must beat the generic
|
|
89
|
+
# api_error fallback so the dashboard + MCP can tell the user to run
|
|
90
|
+
# `claude /login` instead of mis-reporting a benign empty plan. The two
|
|
91
|
+
# phrases below are CLI-specific and don't appear in scraped tweet bodies.
|
|
92
|
+
("claude_not_logged_in", [
|
|
93
|
+
r"not logged in",
|
|
94
|
+
r"please run /login",
|
|
95
|
+
]),
|
|
96
|
+
# Generic Anthropic-side error fallback. Fires when `is_error:true` shows
|
|
97
|
+
# up in the JSONL envelope but none of the more specific patterns matched.
|
|
98
|
+
# Lets the operator see "failed: api_error" instead of nothing at all.
|
|
99
|
+
#
|
|
100
|
+
# NOTE: platform/browser-level errors (auth redirects, RATE_LIMITED_TWITTER,
|
|
101
|
+
# browser navigation timeouts, posting_blocked) are deliberately NOT
|
|
102
|
+
# classified here — they're already covered by per-pipeline cascades in
|
|
103
|
+
# run-twitter-cycle.sh / run-reddit-search.sh / engage_reddit.py with
|
|
104
|
+
# stable historical reason keys the dashboard already renders. Keeping
|
|
105
|
+
# those out of this classifier prevents double-counting.
|
|
106
|
+
("api_error", [
|
|
107
|
+
r'"is_error":\s*true',
|
|
108
|
+
r"api error:",
|
|
109
|
+
r"anthropic.*error",
|
|
110
|
+
]),
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def classify(text: str) -> str:
|
|
115
|
+
"""Return the first matching reason key, or '' if nothing matched."""
|
|
116
|
+
if not text:
|
|
117
|
+
return ""
|
|
118
|
+
# Pre-lower once; all patterns are case-insensitive anyway, but a single
|
|
119
|
+
# lowercase pass lets us skip the re.IGNORECASE flag overhead on every
|
|
120
|
+
# match attempt against multi-MB log buffers.
|
|
121
|
+
low = text.lower()
|
|
122
|
+
for reason, regexes in PATTERNS:
|
|
123
|
+
for rx in regexes:
|
|
124
|
+
if re.search(rx, low):
|
|
125
|
+
return reason
|
|
126
|
+
return ""
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _read_input(path: str) -> str:
|
|
130
|
+
"""Read text from a path or '-' (stdin). Errors degrade to empty string."""
|
|
131
|
+
if path == "-" or path == "":
|
|
132
|
+
return sys.stdin.read()
|
|
133
|
+
try:
|
|
134
|
+
return Path(path).read_text(errors="replace")
|
|
135
|
+
except (OSError, UnicodeDecodeError):
|
|
136
|
+
return ""
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def main() -> int:
|
|
140
|
+
quiet = False
|
|
141
|
+
args = list(sys.argv[1:])
|
|
142
|
+
if "--quiet" in args:
|
|
143
|
+
quiet = True
|
|
144
|
+
args.remove("--quiet")
|
|
145
|
+
path = args[0] if args else "-"
|
|
146
|
+
text = _read_input(path)
|
|
147
|
+
reason = classify(text)
|
|
148
|
+
if reason:
|
|
149
|
+
print(reason)
|
|
150
|
+
return 0
|
|
151
|
+
if quiet:
|
|
152
|
+
return 1
|
|
153
|
+
print("")
|
|
154
|
+
return 0
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
if __name__ == "__main__":
|
|
158
|
+
sys.exit(main())
|