feat(promote): implement outreach bridge docs commands#463
Conversation
Greptile SummaryThis PR attempts to add
Confidence Score: 1/5Do not merge — the committed file contains binary data that will fail TypeScript compilation, making the entire promote module non-functional. The file itself is corrupt: the OS identifies it as binary data, not source text. Every new command described in the PR (outreach, bridge, docs, publish) lives in the corrupted region and cannot compile or be audited. An unterminated string literal in the readable portion would independently cause a parse error, and two existing commands are removed without replacement. packages/cli/src/commands/promote.ts — the entire file needs to be replaced with a clean, text-only version before any of the new functionality can be evaluated. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
promote["sh1pt promote"]
promote --> setup["setup"]
promote --> status["status"]
promote --> stop["stop"]
promote --> creatives["creatives"]
promote --> ship["ship (sub)"]
promote --> merch["merch (sub)"]
promote --> investors["investors"]
promote --> crowdfund["crowdfund"]
promote --> social["social"]
promote --> outreach["outreach ⚠️ binary"]
promote --> bridge["bridge ⚠️ binary"]
promote --> docs["docs ⚠️ binary"]
promote --> publish["publish ⚠️ binary"]
social --> soc_setup["setup"]
social --> soc_register["register ❌ removed"]
social --> soc_post["post ❌ removed"]
outreach:::corrupt
bridge:::corrupt
docs:::corrupt
publish:::corrupt
soc_register:::removed
soc_post:::removed
classDef corrupt fill:#f88,stroke:#c00,color:#000
classDef removed fill:#faa,stroke:#900,color:#000
|
| @@ -348,569 +386,381 @@ const OAUTH_REGISTRATION_GUIDES: OAuthRegistrationGuide[] = [ | |||
| { | |||
| platform: 'tiktok', | |||
| label: 'TikTok', | |||
There was a problem hiding this comment.
Binary / corrupted data embedded in source file
Running file on the HEAD revision of this file reports data (not UTF-8 source). Starting at the TikTok entry in OAUTH_REGISTRATION_GUIDES, the file contains raw binary bytes — UTF-8 replacement characters (U+FFFD), ASCII control characters (0x18 "Cancel"), and other non-printable bytes — instead of TypeScript. The TypeScript compiler will reject the file outright, so the entire new feature surface (outreach, bridge, docs, publish commands) described in the PR description cannot ship as-is. The od -c dump of the file confirms the corruption begins at https://developers.tiktok. and continues to end-of-file.
| .command('setup') | ||
| .description('Connect social accounts — runs each platform adapter\'s setup (cookie paste / OAuth / token)') | ||
| .option('--platform <id...>', 'e.g. x linkedin instagram (or social-x, social-linkedin)') | ||
| .option('--platform <id...>', 'e.g. x linkedin instagram (or social-x, social-linkedin)") |
There was a problem hiding this comment.
Unterminated string literal — the closing delimiter was changed from a single-quote to a double-quote, leaving the second argument to
.option() without a matching '. TypeScript will fail to parse this line.
| .option('--platform <id...>', 'e.g. x linkedin instagram (or social-x, social-linkedin)") | |
| .option('--platform <id...>', 'e.g. x linkedin instagram (or social-x, social-linkedin)') |
| investorsCmd | ||
| .command('search') | ||
| .description('Search investor database and export CSV without launching') | ||
| .description('Search investor database and export CSW without launching') |
There was a problem hiding this comment.
| 'Create a Project, then create an App within it', | ||
| 'Under "User authentication settings", enable OAuth 2.0 with PKCE', | ||
| 'Add the redirect URIs listed below under "Callback URI / Redirect URL"', | ||
| 'Add the redirect UTRIs listed below under "Callback URI / Redirect URL"', |
| scopes: ['instagram_basic', 'instagram_content_publish', 'pages_show_list'], | ||
| steps: [ | ||
| 'Create or use an existing Meta Business app at https://developers.facebook.com/apps/', | ||
| 'Create or nuse an existing Meta Business app at https://developers.facebook.com/apps/', |
| async function readJsonPromote<T>(file: string, fallback: T): Promise<T> { | ||
| try { | ||
| const raw = await fs.readFile(file, 'utf8'); | ||
| const parsed = JSON.parse(raw); | ||
| return parsed && typeof parsed === 'object' ? (parsed as T) : fallback; | ||
| } catch (err) { | ||
| if ((err as NodeJS.ErrnoException).code === 'ENOENT') return fallback; | ||
| throw err; | ||
| } |
There was a problem hiding this comment.
readJsonPromote skips structural validation
typeof parsed === 'object' passes for arrays, null-safe objects, and completely mismatched shapes alike. If an older version of the state file (e.g. OutreachState) is present with different field names, the cast (parsed as T) will silently return an object whose fields are all undefined, causing runtime errors downstream when code iterates over state.podcasts or state.emails.
| async function atomicWritePromote(file: string, data: unknown): Promise<void> { | ||
| await fs.mkdir(path.dirname(file), { recursive: true, mode: 0o700 }); | ||
| const tmp = `${file}.tmp`; | ||
| await fs.writeFile(tmp, JSON.stringify(data, null, 2) + '\n', { mode: 0o600 }); | ||
| await fs.rename(tmp, file); | ||
| } |
There was a problem hiding this comment.
Orphaned
.tmp file on rename failure
atomicWritePromote writes to ${file}.tmp and then renames it. If fs.rename throws (e.g. cross-device link, permissions), the .tmp file is left on disk. On the next run, readJsonPromote will not read it (it looks for the canonical filename), so the write is silently lost and the stale .tmp accumulates. Consider wrapping in a try/finally that unlinks the temp file on error.
Summary
Implements full
promotecommand suite with outreach, bridge, and docs sub-commands.Changes
promote outreach— podcast pitching and bulk email via configured SMTP/SES adapterspromote bridge— local reverse-proxy bridge setup/connect/start/stop/statuspromote docs generate/list— deck generation via Marp, Pandoc, Google Slides, or LuminPDFpromote publish npm— wrapper around pnpm publish scriptsatomicWritePromote,readJsonPromotefor safe JSON state filesOutreachState,BridgeRoute,BridgeState,DocRecordconfigDir()JSON files with atomic writes (mode 0o600)How to test