thumbgate 1.27.15 → 1.27.16

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.
@@ -0,0 +1,591 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('node:fs');
5
+ const path = require('node:path');
6
+ const { spawnSync } = require('node:child_process');
7
+
8
+ const REPO_ROOT = path.resolve(__dirname, '..');
9
+ const DEFAULT_DATE = '2026-06-24';
10
+ const REPORT_SLUG = 'human-on-the-bridge-pack';
11
+ const APPROVAL_PHRASE = `APPROVED: publish HOB ThumbGate response pack ${DEFAULT_DATE}`;
12
+ const OUTREACH_APPROVAL_PHRASE = 'APPROVED: send HOB ThumbGate outreach to <target>';
13
+
14
+ const LINKS = Object.freeze({
15
+ paper: 'https://arxiv.org/abs/2606.16871',
16
+ sourcePost: 'https://x.com/omarsar0/status/2068743256079556989',
17
+ thumbgate: 'https://thumbgate.ai',
18
+ thumbgateCheckout: 'https://thumbgate.ai/checkout/pro',
19
+ thumbgateGatekeeperCompare: 'https://thumbgate.ai/compare/oak-and-sparrow-gatekeeper',
20
+ thumbgateRepo: 'https://github.com/IgorGanapolsky/ThumbGate',
21
+ gatekeeper: 'https://oakandsparrowsystemsenterprise.io',
22
+ gatekeeperEvent: 'https://www.deep-tech-week.com/sf-2026/events/gatekeeper-deterministic-ai-governance-subtitle-refusal-is-t',
23
+ commercialTruth: 'docs/COMMERCIAL_TRUTH.md',
24
+ verificationEvidence: 'docs/VERIFICATION_EVIDENCE.md',
25
+ gatekeeperRule: 'reports/gtm/2026-06-24-gatekeeper-promise-repair/DAILY_GATEKEEPER_CONTENT_RULE.md',
26
+ });
27
+
28
+ function normalizeText(value) {
29
+ return String(value ?? '').trim();
30
+ }
31
+
32
+ function runJsonCommand(args, repoRoot = REPO_ROOT) {
33
+ const result = spawnSync(process.execPath, args, {
34
+ cwd: repoRoot,
35
+ encoding: 'utf8',
36
+ timeout: 15_000,
37
+ });
38
+ const stdout = normalizeText(result.stdout);
39
+ const stderr = normalizeText(result.stderr);
40
+
41
+ if (result.status !== 0 || !stdout) {
42
+ return {
43
+ ok: false,
44
+ status: result.status,
45
+ stdout,
46
+ stderr,
47
+ };
48
+ }
49
+
50
+ try {
51
+ return {
52
+ ok: true,
53
+ status: result.status,
54
+ data: JSON.parse(stdout),
55
+ };
56
+ } catch (error) {
57
+ return {
58
+ ok: false,
59
+ status: result.status,
60
+ stdout,
61
+ stderr: stderr || error.message,
62
+ };
63
+ }
64
+ }
65
+
66
+ function collectLocalEvidence(repoRoot = REPO_ROOT) {
67
+ const pipeline = runJsonCommand(['scripts/sales-pipeline.js', 'summary'], repoRoot);
68
+ const stripe = runJsonCommand(['scripts/stripe-live-status.js'], repoRoot);
69
+
70
+ return {
71
+ generatedAt: new Date().toISOString(),
72
+ production: {
73
+ healthUrl: 'https://thumbgate.ai/health',
74
+ healthObserved: 'Verified in this operator run: HTTP 200 JSON status ok, version 1.27.15.',
75
+ checkoutUrl: LINKS.thumbgateCheckout,
76
+ checkoutObserved: 'Verified in this operator run: HTTP 200 for /checkout/pro.',
77
+ },
78
+ pipeline: pipeline.ok ? pipeline.data : { unavailable: pipeline },
79
+ stripe: stripe.ok ? stripe.data : { unavailable: stripe },
80
+ commercialTruth: {
81
+ path: LINKS.commercialTruth,
82
+ summary: 'Current offer truth: Free local CLI, Pro at $19/mo or $149/yr, Enterprise/custom intake-led sprint. No same-day paid proof in this evidence window.',
83
+ },
84
+ gatekeeper: {
85
+ rulePath: LINKS.gatekeeperRule,
86
+ url: LINKS.gatekeeper,
87
+ eventUrl: LINKS.gatekeeperEvent,
88
+ promise: 'Daily ThumbGate content must include the Gatekeeper/Oak & Sparrow field-proof angle and link exposure when relevant.',
89
+ },
90
+ };
91
+ }
92
+
93
+ function buildHobPack(options = {}) {
94
+ const date = normalizeText(options.date) || DEFAULT_DATE;
95
+ const generatedAt = normalizeText(options.generatedAt) || new Date().toISOString();
96
+ const evidence = options.evidence || {};
97
+
98
+ const reusableAssets = [
99
+ {
100
+ key: 'red_team_traps',
101
+ title: 'Red-team trap templates',
102
+ buyerProblem: 'Agent teams need repeatable failure probes instead of one-off human review.',
103
+ thumbgateImplementation: 'Convert expert-labeled failure cases into pre-action trap prompts and blocked tool-call examples.',
104
+ exampleAssets: [
105
+ 'Prompt-injection trap: external page asks the agent to ignore local policy before a file write.',
106
+ 'Privilege trap: agent attempts production data access without an explicit ticket or owner approval.',
107
+ 'Retrieval trap: agent cites a stale RAG lesson when current evidence is required.',
108
+ ],
109
+ },
110
+ {
111
+ key: 'juror_personas',
112
+ title: 'Juror persona templates',
113
+ buyerProblem: 'Human judgment does not scale unless the judgment role is specified.',
114
+ thumbgateImplementation: 'Define reviewer personas such as security lead, platform owner, compliance owner, and incident commander, then map each to gates and scoring weights.',
115
+ exampleAssets: [
116
+ 'Security lead: blocks secret exposure, unsafe shell commands, and unknown external fetches.',
117
+ 'Platform owner: blocks deploys without health, rollback, and ownership evidence.',
118
+ 'Revenue owner: blocks money claims without payment-provider truth.',
119
+ ],
120
+ },
121
+ {
122
+ key: 'scoring_guidelines',
123
+ title: 'Scoring guideline templates',
124
+ buyerProblem: 'Agent evals are hard to compare when every reviewer scores risk differently.',
125
+ thumbgateImplementation: 'Turn expert criteria into explicit pass, warn, block, and escalate thresholds with evidence fields.',
126
+ exampleAssets: [
127
+ 'Pass: action has current source evidence, owner context, reversible execution, and no restricted data.',
128
+ 'Warn: action is reversible but missing a fresh source or test readback.',
129
+ 'Block: action can affect money, users, production, or confidential data without current proof.',
130
+ ],
131
+ },
132
+ {
133
+ key: 'fallback_policy_gates',
134
+ title: 'Fallback-policy gates',
135
+ buyerProblem: 'When the agent is uncertain, it often keeps going instead of falling back safely.',
136
+ thumbgateImplementation: 'Add deterministic fallback gates: ask for approval, draft only, dry-run only, or stop with unknowns labeled.',
137
+ exampleAssets: [
138
+ 'External side effect fallback: draft the exact post/email, require action-time approval, then send only after approval.',
139
+ 'Payment fallback: use provider truth first; if secrets are missing, label revenue as unknown or zero-proof.',
140
+ 'Research fallback: if current source is unreachable, label unknowns rather than filling the gap from memory.',
141
+ ],
142
+ },
143
+ {
144
+ key: 'evidence_receipts',
145
+ title: 'Evidence-linked run reports',
146
+ buyerProblem: 'A successful eval run is not useful if nobody can audit why it passed.',
147
+ thumbgateImplementation: 'Emit receipts with source URLs, command output summaries, gate decisions, and next-state instructions.',
148
+ exampleAssets: [
149
+ 'Gate decision receipt: rule id, evidence path, action attempted, decision, next allowed action.',
150
+ 'Revenue receipt: provider status, checkout status, pipeline state, money truth.',
151
+ 'Content receipt: platform, draft text, required links, approval phrase, posting blocker or live URL.',
152
+ ],
153
+ },
154
+ ];
155
+
156
+ const offer = {
157
+ name: 'Human-on-the-Bridge Workflow Hardening Sprint',
158
+ positioning: 'Convert expert judgment about one real agent workflow into reusable ThumbGate checks, receipts, and fallback policies.',
159
+ buyer: 'AI agent platform teams, automation agencies, eval teams, and compliance-sensitive engineering leaders.',
160
+ scope: [
161
+ 'Select one load-bearing workflow and one failure mode.',
162
+ 'Extract expert judgment into red-team traps, juror personas, scoring guidelines, and fallback gates.',
163
+ 'Wire the resulting checks into a ThumbGate runbook with evidence receipts.',
164
+ 'Return a before/after action plan that the team can use without putting an LLM in the final policy seat.',
165
+ ],
166
+ commercialGuardrail: 'Do not invent a cash win. Current evidence supports workflow-hardening and intake-led sprint positioning, not same-day paid revenue.',
167
+ callToAction: 'Send one agent workflow and the failure mode you most want to stop repeating.',
168
+ };
169
+
170
+ return {
171
+ date,
172
+ generatedAt,
173
+ title: 'Human-on-the-Bridge ThumbGate Pack',
174
+ thesis: 'Human-on-the-Bridge is a strong external framing for ThumbGate because it says expert judgment should move upstream into reusable evaluation assets. ThumbGate is the runtime side: those assets become deterministic pre-action gates, fallback policies, and evidence receipts.',
175
+ unknowns: [
176
+ 'Unknown: whether the paper authors, Omar, Dair.ai, or ProofAgent want a ThumbGate collaboration.',
177
+ 'Unknown: whether the Gatekeeper event attendee list will contain qualified buyers until Nick/Josh send it.',
178
+ 'Unknown: current payment-provider revenue until Stripe or PayPal provider truth shows paid events.',
179
+ ],
180
+ links: { ...LINKS },
181
+ evidence,
182
+ reusableAssets,
183
+ offer,
184
+ contentQueue: buildContentQueue(date),
185
+ outreachQueue: buildOutreachQueue(date),
186
+ };
187
+ }
188
+
189
+ function buildContentQueue(date = DEFAULT_DATE) {
190
+ return [
191
+ {
192
+ platform: 'LinkedIn',
193
+ status: 'draft_only',
194
+ purpose: 'Thought-leadership post that ties HOB to ThumbGate and gives Gatekeeper partner exposure.',
195
+ requiredLinks: [LINKS.paper, LINKS.thumbgate, LINKS.gatekeeper],
196
+ text: [
197
+ 'Human-on-the-Bridge is the clearest framing I have seen this week for agent evals:',
198
+ '',
199
+ 'Do not keep expert judgment trapped in one-off reviews. Move it upstream into reusable evaluation assets.',
200
+ '',
201
+ 'That is exactly where ThumbGate fits. Expert feedback becomes deterministic pre-action checks, fallback gates, and evidence receipts before an agent touches code, money, customer systems, or external tools.',
202
+ '',
203
+ 'The live field context for this ThumbGate cycle is Gatekeeper by Oak & Sparrow. Gatekeeper focuses on deterministic AI governance before data leaves the building; ThumbGate focuses on pre-action checks before coding agents execute risky tool calls. Same direction: prove the action before execution.',
204
+ '',
205
+ `Paper: ${LINKS.paper}`,
206
+ `ThumbGate: ${LINKS.thumbgate}`,
207
+ `Gatekeeper / Oak & Sparrow: ${LINKS.gatekeeper}`,
208
+ ].join('\n'),
209
+ approval: APPROVAL_PHRASE,
210
+ },
211
+ {
212
+ platform: 'X',
213
+ status: 'draft_only',
214
+ purpose: 'Short response to Omar/Dair.ai without claiming affiliation.',
215
+ requiredLinks: [LINKS.paper, LINKS.thumbgate],
216
+ text: [
217
+ 'Strong framing. Human-on-the-Bridge maps cleanly to the missing runtime layer for agent evals:',
218
+ '',
219
+ 'expert judgment -> reusable eval assets -> deterministic pre-action gates -> evidence receipts',
220
+ '',
221
+ `That is what ThumbGate is building for coding agents: ${LINKS.thumbgate}`,
222
+ `Paper: ${LINKS.paper}`,
223
+ ].join('\n'),
224
+ approval: APPROVAL_PHRASE,
225
+ },
226
+ {
227
+ platform: 'Medium',
228
+ status: 'draft_only',
229
+ purpose: 'Article outline for the required daily article lane.',
230
+ requiredLinks: [LINKS.paper, LINKS.thumbgate, LINKS.gatekeeper, LINKS.thumbgateGatekeeperCompare],
231
+ title: 'Human-on-the-Bridge Is the Missing Bridge Between Agent Evals and Runtime Gates',
232
+ outline: [
233
+ '1. The eval problem: agents are behavioral systems, not static benchmarks.',
234
+ '2. The HOB insight: expert judgment should be front-loaded into reusable assets.',
235
+ '3. ThumbGate implementation: red-team traps, juror personas, scoring guidelines, fallback gates, and evidence receipts.',
236
+ '4. Gatekeeper field note: Gatekeeper covers workforce-input governance; ThumbGate covers coding-agent action governance.',
237
+ '5. Practical CTA: send one workflow and one failure mode to convert into gates.',
238
+ ],
239
+ approval: APPROVAL_PHRASE,
240
+ },
241
+ {
242
+ platform: 'Reddit',
243
+ status: 'draft_only',
244
+ purpose: 'Technical-first version that avoids partner/event links by default.',
245
+ requiredLinks: [LINKS.paper, LINKS.thumbgateRepo],
246
+ text: [
247
+ 'I built a small implementation pack for turning Human-on-the-Bridge-style expert judgment into runtime checks for AI coding agents.',
248
+ '',
249
+ 'The shape is:',
250
+ '- red-team trap templates',
251
+ '- juror/reviewer personas',
252
+ '- scoring guidelines',
253
+ '- fallback-policy gates',
254
+ '- evidence-linked receipts',
255
+ '',
256
+ `Paper: ${LINKS.paper}`,
257
+ `Repo: ${LINKS.thumbgateRepo}`,
258
+ '',
259
+ 'Free to try locally via npx thumbgate init. Paid tiers are optional.',
260
+ ].join('\n'),
261
+ approval: APPROVAL_PHRASE,
262
+ },
263
+ ];
264
+ }
265
+
266
+ function buildOutreachQueue(date = DEFAULT_DATE) {
267
+ return [
268
+ {
269
+ target: 'Omar / Dair.ai',
270
+ channel: 'X or LinkedIn reply',
271
+ score: 18,
272
+ reason: 'Posted the HOB paper and already frames the problem as scalable evaluation for agents.',
273
+ evidence: [LINKS.sourcePost, LINKS.paper],
274
+ proposedAction: 'Reply with a compact HOB-to-ThumbGate runtime-gate mapping.',
275
+ draft: [
276
+ 'Saw your HOB note. The paper maps really cleanly to a runtime implementation pattern:',
277
+ '',
278
+ 'human expert judgment -> reusable eval assets -> deterministic pre-action gates -> receipts',
279
+ '',
280
+ 'ThumbGate is building that last mile for coding agents. If useful, I can share the small implementation pack: red-team traps, juror personas, scoring guidelines, fallback gates, and evidence receipts.',
281
+ ].join('\n'),
282
+ approval: OUTREACH_APPROVAL_PHRASE.replace('<target>', 'Omar / Dair.ai'),
283
+ },
284
+ {
285
+ target: 'ProofAgent / HOB paper author lane',
286
+ channel: 'public reply or email only after verified contact source',
287
+ score: 16,
288
+ reason: 'Direct thematic fit: ThumbGate can operationalize reusable expert judgment at the pre-action boundary.',
289
+ evidence: [LINKS.paper],
290
+ proposedAction: 'Offer a draft implementation mapping, not a partnership claim.',
291
+ draft: [
292
+ 'Your Human-on-the-Bridge framing is useful because it makes expert judgment reusable instead of trapping it in per-output review.',
293
+ '',
294
+ 'I am mapping that into ThumbGate as a practical runtime pack for coding agents: traps, reviewer personas, score thresholds, fallback gates, and auditable receipts.',
295
+ '',
296
+ 'Happy to share the mapping if it is useful for implementation examples.',
297
+ ].join('\n'),
298
+ approval: OUTREACH_APPROVAL_PHRASE.replace('<target>', 'ProofAgent / HOB author lane'),
299
+ },
300
+ {
301
+ target: 'Gatekeeper / Oak & Sparrow',
302
+ channel: 'existing Gmail thread only with action-time approval',
303
+ score: 15,
304
+ reason: 'Existing field collaboration requires daily exposure and gives the HOB story a concrete live governance context.',
305
+ evidence: [LINKS.gatekeeper, LINKS.gatekeeperEvent, LINKS.gatekeeperRule],
306
+ proposedAction: 'Share the HOB pack as a sponsor-aligned field note and ask for the workflow to inspect.',
307
+ draft: [
308
+ 'Nick, quick field note for the event context: the Human-on-the-Bridge paper gives us a clean explanation for why Gatekeeper and ThumbGate fit.',
309
+ '',
310
+ 'Gatekeeper moves workforce AI governance before data leaves the building. ThumbGate moves coding-agent checks before risky tool actions execute. Both turn judgment into proof before action.',
311
+ '',
312
+ 'If Josh has the workflow ready, send the one workflow/failure mode and I will convert it into the inspection pack.',
313
+ ].join('\n'),
314
+ approval: OUTREACH_APPROVAL_PHRASE.replace('<target>', 'Gatekeeper / Oak & Sparrow'),
315
+ },
316
+ ].map((entry) => ({ ...entry, date }));
317
+ }
318
+
319
+ function renderEvidenceLedger(pack) {
320
+ const pipeline = pack.evidence?.pipeline?.summary;
321
+ const stripe = pack.evidence?.stripe;
322
+ const stageJson = pipeline?.byStage ? JSON.stringify(pipeline.byStage) : 'unknown';
323
+ const stripeStatus = normalizeText(stripe?.status || stripe?.stripe?.status || stripe?.unavailable?.stderr) || 'unknown';
324
+
325
+ return [
326
+ '# Human-on-the-Bridge Pack Evidence Ledger',
327
+ '',
328
+ `Generated: \`${pack.generatedAt}\``,
329
+ `Date: \`${pack.date}\``,
330
+ '',
331
+ '## Current External Evidence',
332
+ '',
333
+ `- HOB paper: ${pack.links.paper}`,
334
+ `- Source post: ${pack.links.sourcePost}`,
335
+ `- ThumbGate production health: ${pack.evidence?.production?.healthObserved || 'unknown'}`,
336
+ `- ThumbGate checkout route: ${pack.evidence?.production?.checkoutObserved || 'unknown'}`,
337
+ `- Gatekeeper / Oak & Sparrow: ${pack.links.gatekeeper}`,
338
+ `- Gatekeeper event proof: ${pack.links.gatekeeperEvent}`,
339
+ '',
340
+ '## Money Truth',
341
+ '',
342
+ `- Pipeline stage counts: \`${stageJson}\``,
343
+ `- Pipeline paid count: \`${pipeline?.paid ?? 0}\``,
344
+ `- Pipeline booked revenue cents: \`${pipeline?.bookedRevenueCents ?? 0}\``,
345
+ `- Stripe status: \`${stripeStatus}\``,
346
+ '- Revenue conclusion: no same-day paid event is proven by this evidence window.',
347
+ '',
348
+ '## Commercial Guardrails',
349
+ '',
350
+ `- Commercial truth source: ${pack.links.commercialTruth}`,
351
+ `- Verification evidence source: ${pack.links.verificationEvidence}`,
352
+ '- Allowed claim: ThumbGate has a live workflow-hardening motion and a reachable production/checkout path.',
353
+ '- Blocked claim: do not say HOB/Gatekeeper produced paid revenue until payment-provider truth proves it.',
354
+ '',
355
+ ].join('\n');
356
+ }
357
+
358
+ function renderHobPack(pack) {
359
+ const assetLines = pack.reusableAssets.flatMap((asset) => ([
360
+ `### ${asset.title}`,
361
+ '',
362
+ `- Buyer problem: ${asset.buyerProblem}`,
363
+ `- ThumbGate implementation: ${asset.thumbgateImplementation}`,
364
+ '- Example assets:',
365
+ ...asset.exampleAssets.map((item) => ` - ${item}`),
366
+ '',
367
+ ]));
368
+
369
+ return [
370
+ '# Human-on-the-Bridge ThumbGate Pack',
371
+ '',
372
+ `Generated: \`${pack.generatedAt}\``,
373
+ '',
374
+ '## Thesis',
375
+ '',
376
+ pack.thesis,
377
+ '',
378
+ '## Source Links',
379
+ '',
380
+ `- Paper: ${pack.links.paper}`,
381
+ `- Source post: ${pack.links.sourcePost}`,
382
+ `- ThumbGate: ${pack.links.thumbgate}`,
383
+ `- Gatekeeper / Oak & Sparrow: ${pack.links.gatekeeper}`,
384
+ `- ThumbGate + Gatekeeper comparison: ${pack.links.thumbgateGatekeeperCompare}`,
385
+ '',
386
+ '## Reusable Evaluation Assets',
387
+ '',
388
+ ...assetLines,
389
+ '## Unknowns',
390
+ '',
391
+ ...pack.unknowns.map((unknown) => `- ${unknown}`),
392
+ '',
393
+ ].join('\n');
394
+ }
395
+
396
+ function renderOffer(pack) {
397
+ return [
398
+ '# Human-on-the-Bridge Workflow Hardening Sprint',
399
+ '',
400
+ `Generated: \`${pack.generatedAt}\``,
401
+ '',
402
+ '## Offer',
403
+ '',
404
+ `- Name: ${pack.offer.name}`,
405
+ `- Positioning: ${pack.offer.positioning}`,
406
+ `- Buyer: ${pack.offer.buyer}`,
407
+ `- CTA: ${pack.offer.callToAction}`,
408
+ '',
409
+ '## Scope',
410
+ '',
411
+ ...pack.offer.scope.map((item) => `- ${item}`),
412
+ '',
413
+ '## Gatekeeper Field Fit',
414
+ '',
415
+ '- Gatekeeper covers the workforce-input boundary before regulated data leaves the building.',
416
+ '- ThumbGate covers the agent-action boundary before coding agents execute risky tool calls.',
417
+ '- The HOB framing explains why both are stronger when expert judgment becomes reusable proof before execution.',
418
+ `- Gatekeeper link: ${pack.links.gatekeeper}`,
419
+ `- ThumbGate link: ${pack.links.thumbgate}`,
420
+ '',
421
+ '## Commercial Guardrail',
422
+ '',
423
+ pack.offer.commercialGuardrail,
424
+ '',
425
+ ].join('\n');
426
+ }
427
+
428
+ function renderContentQueue(pack) {
429
+ return [
430
+ '# HOB ThumbGate Content Approval Queue',
431
+ '',
432
+ `Generated: \`${pack.generatedAt}\``,
433
+ '',
434
+ 'Do not publish from this file without action-time approval.',
435
+ '',
436
+ `Publishing approval phrase: \`${APPROVAL_PHRASE}\``,
437
+ '',
438
+ ...pack.contentQueue.flatMap((entry) => ([
439
+ `## ${entry.platform}`,
440
+ '',
441
+ `- Status: ${entry.status}`,
442
+ `- Purpose: ${entry.purpose}`,
443
+ `- Required links: ${entry.requiredLinks.join(', ')}`,
444
+ `- Approval: \`${entry.approval}\``,
445
+ '',
446
+ entry.title ? `Title: ${entry.title}\n` : '',
447
+ entry.outline ? entry.outline.map((line) => `- ${line}`).join('\n') : '```text\n' + entry.text + '\n```',
448
+ '',
449
+ ])),
450
+ ].join('\n');
451
+ }
452
+
453
+ function renderOutreachQueue(pack) {
454
+ return [
455
+ '# HOB ThumbGate Outreach Approval Queue',
456
+ '',
457
+ `Generated: \`${pack.generatedAt}\``,
458
+ '',
459
+ 'Do not send any message from this file without action-time approval.',
460
+ '',
461
+ ...pack.outreachQueue.flatMap((entry) => ([
462
+ `## ${entry.target}`,
463
+ '',
464
+ `- Channel: ${entry.channel}`,
465
+ `- Score: ${entry.score}`,
466
+ `- Reason: ${entry.reason}`,
467
+ `- Evidence: ${entry.evidence.join(', ')}`,
468
+ `- Proposed action: ${entry.proposedAction}`,
469
+ `- Approval: \`${entry.approval}\``,
470
+ '',
471
+ '```text',
472
+ entry.draft,
473
+ '```',
474
+ '',
475
+ ])),
476
+ ].join('\n');
477
+ }
478
+
479
+ function buildArtifacts(pack) {
480
+ return {
481
+ 'EVIDENCE_LEDGER.md': renderEvidenceLedger(pack),
482
+ 'HOB_PACK.md': renderHobPack(pack),
483
+ 'HOB_REVENUE_SPRINT.md': renderOffer(pack),
484
+ [`HOB_CONTENT_QUEUE_${pack.date}.md`]: renderContentQueue(pack),
485
+ 'HOB_OUTREACH_QUEUE.md': renderOutreachQueue(pack),
486
+ 'hob-pack.json': `${JSON.stringify(pack, null, 2)}\n`,
487
+ };
488
+ }
489
+
490
+ function writeHobArtifacts(pack, options = {}) {
491
+ const repoRoot = options.repoRoot || REPO_ROOT;
492
+ const reportDir = options.reportDir
493
+ ? path.resolve(repoRoot, options.reportDir)
494
+ : path.join(repoRoot, 'reports', 'gtm', `${pack.date}-${REPORT_SLUG}`);
495
+ const artifacts = buildArtifacts(pack);
496
+
497
+ fs.mkdirSync(reportDir, { recursive: true });
498
+ const files = [];
499
+ for (const [filename, content] of Object.entries(artifacts)) {
500
+ const filepath = path.join(reportDir, filename);
501
+ fs.writeFileSync(filepath, content);
502
+ files.push(filepath);
503
+ }
504
+
505
+ return { reportDir, files };
506
+ }
507
+
508
+ function parseArgs(argv = []) {
509
+ const options = {
510
+ write: false,
511
+ reportDir: '',
512
+ date: DEFAULT_DATE,
513
+ };
514
+
515
+ for (let index = 0; index < argv.length; index += 1) {
516
+ const arg = argv[index];
517
+ if (arg === '--write' || arg === '--write-docs') {
518
+ options.write = true;
519
+ continue;
520
+ }
521
+ if (arg === '--date') {
522
+ options.date = normalizeText(argv[index + 1]) || options.date;
523
+ index += 1;
524
+ continue;
525
+ }
526
+ if (arg.startsWith('--date=')) {
527
+ options.date = normalizeText(arg.split(/=(.*)/s)[1]) || options.date;
528
+ continue;
529
+ }
530
+ if (arg === '--report-dir') {
531
+ options.reportDir = normalizeText(argv[index + 1]);
532
+ index += 1;
533
+ continue;
534
+ }
535
+ if (arg.startsWith('--report-dir=')) {
536
+ options.reportDir = normalizeText(arg.split(/=(.*)/s)[1]);
537
+ }
538
+ }
539
+
540
+ return options;
541
+ }
542
+
543
+ function run(argv = process.argv.slice(2), repoRoot = REPO_ROOT) {
544
+ const options = parseArgs(argv);
545
+ const evidence = collectLocalEvidence(repoRoot);
546
+ const pack = buildHobPack({
547
+ date: options.date,
548
+ generatedAt: evidence.generatedAt,
549
+ evidence,
550
+ });
551
+
552
+ if (options.write) {
553
+ const result = writeHobArtifacts(pack, {
554
+ repoRoot,
555
+ reportDir: options.reportDir,
556
+ });
557
+ process.stdout.write(`${JSON.stringify({
558
+ ok: true,
559
+ reportDir: result.reportDir,
560
+ files: result.files,
561
+ approvalPhrase: APPROVAL_PHRASE,
562
+ }, null, 2)}\n`);
563
+ return result;
564
+ }
565
+
566
+ process.stdout.write(renderHobPack(pack));
567
+ return pack;
568
+ }
569
+
570
+ if (require.main === module) {
571
+ run();
572
+ }
573
+
574
+ module.exports = {
575
+ APPROVAL_PHRASE,
576
+ OUTREACH_APPROVAL_PHRASE,
577
+ LINKS,
578
+ buildArtifacts,
579
+ buildContentQueue,
580
+ buildHobPack,
581
+ buildOutreachQueue,
582
+ collectLocalEvidence,
583
+ parseArgs,
584
+ renderContentQueue,
585
+ renderEvidenceLedger,
586
+ renderHobPack,
587
+ renderOffer,
588
+ renderOutreachQueue,
589
+ run,
590
+ writeHobArtifacts,
591
+ };