@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,200 @@
|
|
|
1
|
+
// Durable onboarding ledger + structured Doctor integration.
|
|
2
|
+
//
|
|
3
|
+
// The ledger is local and authoritative. Backend delivery is deliberately
|
|
4
|
+
// best-effort: only redacted event metadata is sent, and an offline API never
|
|
5
|
+
// blocks setup. The shared CommonJS modules are also consumed by bin/cli.js, so
|
|
6
|
+
// CLI and MCP use the exact same Doctor checks and JSON file contract.
|
|
7
|
+
import fs from "node:fs";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import { createRequire } from "node:module";
|
|
10
|
+
import { repoDir, run } from "./repo.js";
|
|
11
|
+
import { resolvePython } from "./runtime.js";
|
|
12
|
+
const require = createRequire(import.meta.url);
|
|
13
|
+
export const ONBOARDING_MILESTONES = [
|
|
14
|
+
"environment_checked",
|
|
15
|
+
"runtime_ready",
|
|
16
|
+
"x_connected",
|
|
17
|
+
"profile_scanned",
|
|
18
|
+
"mode_chosen",
|
|
19
|
+
"project_ready",
|
|
20
|
+
"topics_seeded",
|
|
21
|
+
"tasks_scheduled",
|
|
22
|
+
];
|
|
23
|
+
const ledgerApi = require("../shared/onboarding-ledger.cjs");
|
|
24
|
+
const doctorApi = require("../shared/doctor.cjs");
|
|
25
|
+
export function onboardingSnapshot() {
|
|
26
|
+
return ledgerApi.publicSnapshot();
|
|
27
|
+
}
|
|
28
|
+
export function onboardingLedger() {
|
|
29
|
+
return ledgerApi.readLedger();
|
|
30
|
+
}
|
|
31
|
+
export function recordOnboardingAttempt(milestone, metadata = {}) {
|
|
32
|
+
const ledger = ledgerApi.recordAttempt(milestone, metadata);
|
|
33
|
+
void flushOnboardingEvents();
|
|
34
|
+
return ledger;
|
|
35
|
+
}
|
|
36
|
+
export function completeOnboardingMilestone(milestone, metadata = {}) {
|
|
37
|
+
const ledger = ledgerApi.completeMilestone(milestone, metadata);
|
|
38
|
+
void flushOnboardingEvents();
|
|
39
|
+
return ledger;
|
|
40
|
+
}
|
|
41
|
+
export function blockOnboardingMilestone(milestone, code, message, metadata = {}) {
|
|
42
|
+
const ledger = ledgerApi.blockMilestone(milestone, code, message, metadata);
|
|
43
|
+
void flushOnboardingEvents();
|
|
44
|
+
return ledger;
|
|
45
|
+
}
|
|
46
|
+
export async function runDoctorPhase(phase) {
|
|
47
|
+
const report = doctorApi.runDoctorSync({
|
|
48
|
+
phase,
|
|
49
|
+
repoDir: repoDir(),
|
|
50
|
+
python: resolvePython(),
|
|
51
|
+
});
|
|
52
|
+
ledgerApi.recordDoctorReport(report);
|
|
53
|
+
await flushOnboardingEvents();
|
|
54
|
+
return report;
|
|
55
|
+
}
|
|
56
|
+
// Run each phase once automatically during onboarding. A direct doctor tool call
|
|
57
|
+
// can still force another historical run.
|
|
58
|
+
export async function ensureDoctorPhase(phase) {
|
|
59
|
+
const runs = onboardingLedger()?.doctor?.runs;
|
|
60
|
+
const existing = Array.isArray(runs)
|
|
61
|
+
? [...runs].reverse().find((run) => run?.phase === phase)
|
|
62
|
+
: null;
|
|
63
|
+
return existing || runDoctorPhase(phase);
|
|
64
|
+
}
|
|
65
|
+
function safeNumber(value) {
|
|
66
|
+
const n = Number(value);
|
|
67
|
+
return Number.isFinite(n) ? n : undefined;
|
|
68
|
+
}
|
|
69
|
+
function safeString(value, max = 80) {
|
|
70
|
+
if (typeof value !== "string")
|
|
71
|
+
return undefined;
|
|
72
|
+
const clean = value.trim().replace(/\s+/g, "_").slice(0, max);
|
|
73
|
+
return clean || undefined;
|
|
74
|
+
}
|
|
75
|
+
// Strict allowlist: local events can contain useful human-readable diagnostics,
|
|
76
|
+
// but the API receives only coarse states/counts/codes and Doctor check statuses.
|
|
77
|
+
function redactMetadata(event) {
|
|
78
|
+
const source = event.metadata || {};
|
|
79
|
+
const out = {};
|
|
80
|
+
for (const key of ["phase", "outcome", "state"]) {
|
|
81
|
+
const value = safeString(source[key]);
|
|
82
|
+
if (value)
|
|
83
|
+
out[key] = value;
|
|
84
|
+
}
|
|
85
|
+
for (const key of [
|
|
86
|
+
"missing_count",
|
|
87
|
+
"topic_count",
|
|
88
|
+
"draft_count",
|
|
89
|
+
"exit_code",
|
|
90
|
+
]) {
|
|
91
|
+
const value = safeNumber(source[key]);
|
|
92
|
+
if (value !== undefined)
|
|
93
|
+
out[key] = value;
|
|
94
|
+
}
|
|
95
|
+
if (typeof source.ok === "boolean")
|
|
96
|
+
out.ok = source.ok;
|
|
97
|
+
const summary = source.summary;
|
|
98
|
+
if (summary && typeof summary === "object") {
|
|
99
|
+
const s = summary;
|
|
100
|
+
out.summary = Object.fromEntries(["pass", "fail", "expected", "warn", "total"]
|
|
101
|
+
.map((key) => [key, safeNumber(s[key])])
|
|
102
|
+
.filter((entry) => entry[1] !== undefined));
|
|
103
|
+
}
|
|
104
|
+
const statuses = source.check_statuses;
|
|
105
|
+
if (statuses && typeof statuses === "object") {
|
|
106
|
+
out.check_statuses = Object.fromEntries(Object.entries(statuses)
|
|
107
|
+
.map(([key, value]) => [safeString(key), safeString(value)])
|
|
108
|
+
.filter((entry) => Boolean(entry[0]) && Boolean(entry[1])));
|
|
109
|
+
}
|
|
110
|
+
return out;
|
|
111
|
+
}
|
|
112
|
+
function redactEvent(event) {
|
|
113
|
+
return {
|
|
114
|
+
event_id: event.event_id,
|
|
115
|
+
occurred_at: event.occurred_at,
|
|
116
|
+
milestone: event.milestone,
|
|
117
|
+
type: event.type,
|
|
118
|
+
attempt: event.attempt,
|
|
119
|
+
status: safeString(event.status),
|
|
120
|
+
code: safeString(event.code),
|
|
121
|
+
metadata: redactMetadata(event),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
async function identityHeader() {
|
|
125
|
+
const script = path.join(repoDir(), "scripts", "identity.py");
|
|
126
|
+
if (!fs.existsSync(script))
|
|
127
|
+
return null;
|
|
128
|
+
const result = await run(resolvePython(), [script, "header"], {
|
|
129
|
+
timeoutMs: 15_000,
|
|
130
|
+
});
|
|
131
|
+
const header = result.stdout.trim();
|
|
132
|
+
return result.code === 0 && header ? header : null;
|
|
133
|
+
}
|
|
134
|
+
let flushInFlight = null;
|
|
135
|
+
export function flushOnboardingEvents() {
|
|
136
|
+
if (flushInFlight)
|
|
137
|
+
return flushInFlight;
|
|
138
|
+
flushInFlight = (async () => {
|
|
139
|
+
const header = await identityHeader();
|
|
140
|
+
if (!header) {
|
|
141
|
+
const pending = ledgerApi.pendingBackendEvents().length;
|
|
142
|
+
return {
|
|
143
|
+
sent: 0,
|
|
144
|
+
pending,
|
|
145
|
+
error: "installation identity unavailable",
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
// Onboarding milestones go to the CLOUD RUN host (AUTOPOSTER_LOG_BASE,
|
|
149
|
+
// default app.s4l.ai), the same GCP-logging lane as the raw log stream: the
|
|
150
|
+
// relay console.log()s each event so Cloud Run's runtime ships it to Cloud
|
|
151
|
+
// Logging. NOT the Vercel host (AUTOPOSTER_API_BASE / s4l.ai) the heartbeat
|
|
152
|
+
// still uses — these events are not a DB row anymore.
|
|
153
|
+
const base = (process.env.AUTOPOSTER_LOG_BASE || "https://app.s4l.ai").replace(/\/+$/, "");
|
|
154
|
+
let sent = 0;
|
|
155
|
+
// Re-read after every batch. This catches milestone events appended while a
|
|
156
|
+
// prior network request was in flight, so the final onboarding event is not
|
|
157
|
+
// stranded waiting for some unrelated future tool call.
|
|
158
|
+
for (let batch = 0; batch < 10; batch += 1) {
|
|
159
|
+
const pending = ledgerApi.pendingBackendEvents().slice(0, 50);
|
|
160
|
+
if (pending.length === 0)
|
|
161
|
+
return { sent, pending: 0 };
|
|
162
|
+
const controller = new AbortController();
|
|
163
|
+
const timeout = setTimeout(() => controller.abort(), 5000);
|
|
164
|
+
try {
|
|
165
|
+
const response = await fetch(`${base}/api/v1/installations/onboarding-events`, {
|
|
166
|
+
method: "POST",
|
|
167
|
+
headers: {
|
|
168
|
+
"content-type": "application/json",
|
|
169
|
+
"x-installation": header,
|
|
170
|
+
},
|
|
171
|
+
body: JSON.stringify({ events: pending.map(redactEvent) }),
|
|
172
|
+
signal: controller.signal,
|
|
173
|
+
});
|
|
174
|
+
if (!response.ok) {
|
|
175
|
+
return {
|
|
176
|
+
sent,
|
|
177
|
+
pending: ledgerApi.pendingBackendEvents().length,
|
|
178
|
+
error: `backend returned ${response.status}`,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
ledgerApi.markBackendEventsSent(pending.map((event) => event.event_id));
|
|
182
|
+
sent += pending.length;
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
return {
|
|
186
|
+
sent,
|
|
187
|
+
pending: ledgerApi.pendingBackendEvents().length,
|
|
188
|
+
error: error instanceof Error ? error.message : String(error),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
finally {
|
|
192
|
+
clearTimeout(timeout);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return { sent, pending: ledgerApi.pendingBackendEvents().length };
|
|
196
|
+
})().finally(() => {
|
|
197
|
+
flushInFlight = null;
|
|
198
|
+
});
|
|
199
|
+
return flushInFlight;
|
|
200
|
+
}
|