thumbgate 0.9.10

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.
Files changed (364) hide show
  1. package/.claude-plugin/README.md +134 -0
  2. package/.claude-plugin/bundle/icon.png +0 -0
  3. package/.claude-plugin/bundle/icon.svg +18 -0
  4. package/.claude-plugin/bundle/server/index.js +24 -0
  5. package/.claude-plugin/marketplace.json +36 -0
  6. package/.claude-plugin/plugin.json +21 -0
  7. package/.well-known/mcp/server-card.json +231 -0
  8. package/LICENSE +21 -0
  9. package/README.md +375 -0
  10. package/adapters/README.md +9 -0
  11. package/adapters/amp/skills/thumbgate-feedback/SKILL.md +22 -0
  12. package/adapters/chatgpt/INSTALL.md +83 -0
  13. package/adapters/chatgpt/openapi.yaml +1281 -0
  14. package/adapters/claude/.mcp.json +14 -0
  15. package/adapters/codex/config.toml +9 -0
  16. package/adapters/gemini/function-declarations.json +224 -0
  17. package/adapters/mcp/server-stdio.js +788 -0
  18. package/adapters/opencode/opencode.json +15 -0
  19. package/bin/cli.js +1484 -0
  20. package/bin/memory.sh +64 -0
  21. package/bin/obsidian-sync.sh +20 -0
  22. package/bin/postinstall.js +37 -0
  23. package/config/build-metadata.json +4 -0
  24. package/config/e2e-critical-flows.json +45 -0
  25. package/config/gate-templates.json +77 -0
  26. package/config/gates/claim-verification.json +29 -0
  27. package/config/gates/computer-use.json +39 -0
  28. package/config/gates/default.json +117 -0
  29. package/config/github-about.json +25 -0
  30. package/config/mcp-allowlists.json +135 -0
  31. package/config/model-tiers.json +33 -0
  32. package/config/partner-routing.json +132 -0
  33. package/config/policy-bundles/constrained-v1.json +64 -0
  34. package/config/policy-bundles/default-v1.json +91 -0
  35. package/config/rubrics/default-v1.json +52 -0
  36. package/config/skill-packs/react-testing.json +23 -0
  37. package/config/skill-packs/stripe-integration/references/api-spec.json +1 -0
  38. package/config/skill-packs/stripe-integration/references/webhook-guide.md +3 -0
  39. package/config/skill-specs/pr-reviewer.json +9 -0
  40. package/config/skill-specs/release-status.json +9 -0
  41. package/config/skill-specs/ticket-triage.json +9 -0
  42. package/config/subagent-profiles.json +32 -0
  43. package/config/tessl-tiles.json +29 -0
  44. package/config/thumbgate-settings.managed.json +12 -0
  45. package/openapi/openapi.yaml +1281 -0
  46. package/package.json +283 -0
  47. package/plugins/amp-skill/INSTALL.md +52 -0
  48. package/plugins/amp-skill/SKILL.md +64 -0
  49. package/plugins/claude-codex-bridge/.claude-plugin/plugin.json +22 -0
  50. package/plugins/claude-codex-bridge/.mcp.json +12 -0
  51. package/plugins/claude-codex-bridge/INSTALL.md +43 -0
  52. package/plugins/claude-codex-bridge/README.md +46 -0
  53. package/plugins/claude-codex-bridge/scripts/codex-bridge.js +288 -0
  54. package/plugins/claude-codex-bridge/skills/adversarial-review/SKILL.md +24 -0
  55. package/plugins/claude-codex-bridge/skills/result/SKILL.md +22 -0
  56. package/plugins/claude-codex-bridge/skills/review/SKILL.md +28 -0
  57. package/plugins/claude-codex-bridge/skills/second-pass/SKILL.md +27 -0
  58. package/plugins/claude-codex-bridge/skills/setup/SKILL.md +21 -0
  59. package/plugins/claude-codex-bridge/skills/status/SKILL.md +19 -0
  60. package/plugins/claude-skill/INSTALL.md +55 -0
  61. package/plugins/claude-skill/SKILL.md +46 -0
  62. package/plugins/codex-profile/.codex-plugin/plugin.json +43 -0
  63. package/plugins/codex-profile/.mcp.json +12 -0
  64. package/plugins/codex-profile/AGENTS.md +20 -0
  65. package/plugins/codex-profile/INSTALL.md +66 -0
  66. package/plugins/codex-profile/README.md +37 -0
  67. package/plugins/cursor-marketplace/.cursor-plugin/plugin.json +23 -0
  68. package/plugins/cursor-marketplace/CHANGELOG.md +30 -0
  69. package/plugins/cursor-marketplace/LICENSE +21 -0
  70. package/plugins/cursor-marketplace/README.md +124 -0
  71. package/plugins/cursor-marketplace/agents/reliability-reviewer.md +31 -0
  72. package/plugins/cursor-marketplace/assets/logo-400x400.png +0 -0
  73. package/plugins/cursor-marketplace/commands/capture-feedback.md +33 -0
  74. package/plugins/cursor-marketplace/commands/check-gates.md +25 -0
  75. package/plugins/cursor-marketplace/commands/show-lessons.md +27 -0
  76. package/plugins/cursor-marketplace/hooks/hooks.json +10 -0
  77. package/plugins/cursor-marketplace/mcp.json +12 -0
  78. package/plugins/cursor-marketplace/rules/feedback-capture.mdc +34 -0
  79. package/plugins/cursor-marketplace/rules/pre-action-gates.mdc +30 -0
  80. package/plugins/cursor-marketplace/rules/session-continuity.mdc +28 -0
  81. package/plugins/cursor-marketplace/scripts/gate-check.sh +11 -0
  82. package/plugins/cursor-marketplace/skills/capture-feedback/SKILL.md +47 -0
  83. package/plugins/cursor-marketplace/skills/prevention-rules/SKILL.md +31 -0
  84. package/plugins/cursor-marketplace/skills/recall-context/SKILL.md +30 -0
  85. package/plugins/cursor-marketplace/skills/search-lessons/SKILL.md +33 -0
  86. package/plugins/gemini-extension/INSTALL.md +92 -0
  87. package/plugins/gemini-extension/gemini_prompt.txt +14 -0
  88. package/plugins/gemini-extension/tool_contract.json +45 -0
  89. package/plugins/opencode-profile/INSTALL.md +57 -0
  90. package/public/assets/instagram-card.png +0 -0
  91. package/public/assets/tiktok-agent-memory.mp4 +0 -0
  92. package/public/blog.html +400 -0
  93. package/public/dashboard.html +1093 -0
  94. package/public/guide.html +317 -0
  95. package/public/index.html +1014 -0
  96. package/public/learn/agent-harness-pattern.html +180 -0
  97. package/public/learn/ai-agent-persistent-memory.html +202 -0
  98. package/public/learn/learn.css +45 -0
  99. package/public/learn/mcp-pre-action-gates-explained.html +172 -0
  100. package/public/learn/stop-ai-agent-force-push.html +134 -0
  101. package/public/learn/vibe-coding-safety-net.html +142 -0
  102. package/public/learn.html +213 -0
  103. package/public/lessons.html +650 -0
  104. package/public/vercel.json +8 -0
  105. package/scripts/__pycache__/train_from_feedback.cpython-312.pyc +0 -0
  106. package/scripts/a2ui-engine.js +73 -0
  107. package/scripts/access-anomaly-detector.js +12 -0
  108. package/scripts/adk-consolidator.js +266 -0
  109. package/scripts/agent-readiness.js +220 -0
  110. package/scripts/agent-security-hardening.js +227 -0
  111. package/scripts/agentic-data-pipeline.js +847 -0
  112. package/scripts/analytics-report.js +328 -0
  113. package/scripts/analytics-window.js +158 -0
  114. package/scripts/async-job-runner.js +1001 -0
  115. package/scripts/audit-trail.js +398 -0
  116. package/scripts/auto-promote-gates.js +299 -0
  117. package/scripts/auto-wire-hooks.js +312 -0
  118. package/scripts/autonomous-sales-agent.js +39 -0
  119. package/scripts/autoresearch-runner.js +216 -0
  120. package/scripts/background-agent-governance.js +237 -0
  121. package/scripts/behavioral-extraction.js +97 -0
  122. package/scripts/belief-update.js +84 -0
  123. package/scripts/billing.js +2438 -0
  124. package/scripts/bot-detector.js +50 -0
  125. package/scripts/budget-guard.js +173 -0
  126. package/scripts/build-claude-mcpb.js +189 -0
  127. package/scripts/build-metadata.js +97 -0
  128. package/scripts/check-congruence.js +322 -0
  129. package/scripts/cli-feedback.js +135 -0
  130. package/scripts/cli-telemetry.js +87 -0
  131. package/scripts/cloudflare-dynamic-sandbox.js +315 -0
  132. package/scripts/code-reasoning.js +350 -0
  133. package/scripts/codegraph-context.js +466 -0
  134. package/scripts/commercial-offer.js +56 -0
  135. package/scripts/computer-use-firewall.js +250 -0
  136. package/scripts/context-engine.js +694 -0
  137. package/scripts/contextfs.js +1287 -0
  138. package/scripts/conversation-context.js +119 -0
  139. package/scripts/creator-campaigns.js +239 -0
  140. package/scripts/daemon-manager.js +108 -0
  141. package/scripts/daily-digest.js +11 -0
  142. package/scripts/dashboard-render-spec.js +395 -0
  143. package/scripts/dashboard.js +1058 -0
  144. package/scripts/data-governance.js +173 -0
  145. package/scripts/delegation-runtime.js +900 -0
  146. package/scripts/deploy-gcp.sh +44 -0
  147. package/scripts/deploy-policy.js +263 -0
  148. package/scripts/disagreement-mining.js +315 -0
  149. package/scripts/dispatch-brief.js +159 -0
  150. package/scripts/distribution-surfaces.js +44 -0
  151. package/scripts/dpo-optimizer.js +209 -0
  152. package/scripts/ephemeral-agent-store.js +219 -0
  153. package/scripts/eval-harness.js +56 -0
  154. package/scripts/evolution-state.js +241 -0
  155. package/scripts/experiment-tracker.js +267 -0
  156. package/scripts/export-databricks-bundle.js +242 -0
  157. package/scripts/export-dpo-pairs.js +345 -0
  158. package/scripts/export-kto-pairs.js +310 -0
  159. package/scripts/export-training.js +448 -0
  160. package/scripts/failure-diagnostics.js +558 -0
  161. package/scripts/feedback-attribution.js +313 -0
  162. package/scripts/feedback-fallback.js +111 -0
  163. package/scripts/feedback-history-distiller.js +391 -0
  164. package/scripts/feedback-inbox-read.js +162 -0
  165. package/scripts/feedback-loop.js +1887 -0
  166. package/scripts/feedback-paths.js +145 -0
  167. package/scripts/feedback-quality.js +139 -0
  168. package/scripts/feedback-root-consolidator.js +238 -0
  169. package/scripts/feedback-schema.js +426 -0
  170. package/scripts/feedback-session.js +286 -0
  171. package/scripts/feedback-to-memory.js +185 -0
  172. package/scripts/feedback-to-rules.js +163 -0
  173. package/scripts/filesystem-search.js +404 -0
  174. package/scripts/funnel-analytics.js +35 -0
  175. package/scripts/gate-satisfy.js +42 -0
  176. package/scripts/gate-stats.js +116 -0
  177. package/scripts/gate-templates.js +70 -0
  178. package/scripts/gates-engine.js +816 -0
  179. package/scripts/generate-paperbanana-diagrams.sh +99 -0
  180. package/scripts/generate-pretool-hook.sh +40 -0
  181. package/scripts/github-about.js +350 -0
  182. package/scripts/github-outreach.js +65 -0
  183. package/scripts/gtm-revenue-loop.js +520 -0
  184. package/scripts/hallucination-detector.js +226 -0
  185. package/scripts/hf-papers.js +317 -0
  186. package/scripts/history-distiller.js +200 -0
  187. package/scripts/hook-auto-capture.sh +95 -0
  188. package/scripts/hook-stop-pr-thread-check.sh +68 -0
  189. package/scripts/hook-stop-self-score.sh +51 -0
  190. package/scripts/hook-stop-verify-deploy.sh +31 -0
  191. package/scripts/hook-thumbgate-cache-updater.js +48 -0
  192. package/scripts/hook-verify-before-done.sh +20 -0
  193. package/scripts/hosted-config.js +170 -0
  194. package/scripts/hybrid-feedback-context.js +676 -0
  195. package/scripts/install-mcp.js +159 -0
  196. package/scripts/intent-router.js +392 -0
  197. package/scripts/internal-agent-bootstrap.js +490 -0
  198. package/scripts/jsonl-watcher.js +155 -0
  199. package/scripts/lesson-db.js +613 -0
  200. package/scripts/lesson-inference.js +315 -0
  201. package/scripts/lesson-retrieval.js +95 -0
  202. package/scripts/lesson-rotation.js +137 -0
  203. package/scripts/lesson-search.js +644 -0
  204. package/scripts/lesson-synthesis.js +196 -0
  205. package/scripts/license.js +50 -0
  206. package/scripts/local-model-profile.js +383 -0
  207. package/scripts/markdown-escape.js +12 -0
  208. package/scripts/marketing-experiment.js +671 -0
  209. package/scripts/mcp-config.js +149 -0
  210. package/scripts/mcp-policy.js +99 -0
  211. package/scripts/memalign-recall.js +111 -0
  212. package/scripts/memory-firewall.js +222 -0
  213. package/scripts/memory-migration.js +296 -0
  214. package/scripts/meta-policy.js +194 -0
  215. package/scripts/metered-billing.js +16 -0
  216. package/scripts/model-tier-router.js +301 -0
  217. package/scripts/money-watcher.js +71 -0
  218. package/scripts/multi-hop-recall.js +240 -0
  219. package/scripts/natural-language-harness.js +330 -0
  220. package/scripts/obsidian-export.js +712 -0
  221. package/scripts/operational-dashboard.js +103 -0
  222. package/scripts/operational-summary.js +93 -0
  223. package/scripts/optimize-context.js +17 -0
  224. package/scripts/org-dashboard.js +201 -0
  225. package/scripts/partner-orchestration.js +146 -0
  226. package/scripts/per-step-scoring.js +165 -0
  227. package/scripts/perplexity-marketing.js +466 -0
  228. package/scripts/pii-scanner.js +153 -0
  229. package/scripts/plan-gate.js +154 -0
  230. package/scripts/post-everywhere.js +308 -0
  231. package/scripts/post-to-x-retry.sh +22 -0
  232. package/scripts/post-to-x.js +369 -0
  233. package/scripts/pr-manager.js +236 -0
  234. package/scripts/predictive-insights.js +356 -0
  235. package/scripts/principle-extractor.js +162 -0
  236. package/scripts/pro-features.js +40 -0
  237. package/scripts/pro-local-dashboard.js +174 -0
  238. package/scripts/problem-detail.js +53 -0
  239. package/scripts/product-feedback.js +134 -0
  240. package/scripts/profile-router.js +245 -0
  241. package/scripts/prompt-dlp.js +221 -0
  242. package/scripts/prompt-guard.js +83 -0
  243. package/scripts/prove-adapters.js +863 -0
  244. package/scripts/prove-attribution.js +365 -0
  245. package/scripts/prove-automation.js +653 -0
  246. package/scripts/prove-autoresearch.js +304 -0
  247. package/scripts/prove-claim-verification.js +277 -0
  248. package/scripts/prove-cloudflare-sandbox.js +163 -0
  249. package/scripts/prove-data-pipeline.js +410 -0
  250. package/scripts/prove-data-quality.js +227 -0
  251. package/scripts/prove-evolution.js +352 -0
  252. package/scripts/prove-harnesses.js +287 -0
  253. package/scripts/prove-intelligence.js +259 -0
  254. package/scripts/prove-lancedb.js +371 -0
  255. package/scripts/prove-local-intelligence.js +342 -0
  256. package/scripts/prove-loop-closure.js +263 -0
  257. package/scripts/prove-predictive-insights.js +357 -0
  258. package/scripts/prove-runtime.js +350 -0
  259. package/scripts/prove-seo-gsd.js +234 -0
  260. package/scripts/prove-settings.js +279 -0
  261. package/scripts/prove-subway-upgrades.js +277 -0
  262. package/scripts/prove-tessl.js +229 -0
  263. package/scripts/prove-training-export.js +327 -0
  264. package/scripts/prove-workflow-contract.js +116 -0
  265. package/scripts/prove-xmemory.js +332 -0
  266. package/scripts/publish-decision.js +133 -0
  267. package/scripts/pulse.js +80 -0
  268. package/scripts/rate-limiter.js +125 -0
  269. package/scripts/reddit-dm-outreach.js +182 -0
  270. package/scripts/reddit-monitor-cron.sh +26 -0
  271. package/scripts/reflector-agent.js +221 -0
  272. package/scripts/reminder-engine.js +132 -0
  273. package/scripts/revenue-status.js +472 -0
  274. package/scripts/risk-scorer.js +458 -0
  275. package/scripts/rlaif-self-audit.js +129 -0
  276. package/scripts/rubric-engine.js +230 -0
  277. package/scripts/schedule-manager.js +251 -0
  278. package/scripts/secret-scanner.js +414 -0
  279. package/scripts/self-heal.js +147 -0
  280. package/scripts/self-healing-check.js +188 -0
  281. package/scripts/semantic-layer.js +98 -0
  282. package/scripts/seo-gsd.js +1153 -0
  283. package/scripts/settings-hierarchy.js +214 -0
  284. package/scripts/shieldcortex-memory-firewall-runner.mjs +53 -0
  285. package/scripts/skill-exporter.js +262 -0
  286. package/scripts/skill-generator.js +446 -0
  287. package/scripts/skill-materializer.js +134 -0
  288. package/scripts/skill-packs.js +136 -0
  289. package/scripts/skill-proposer.js +99 -0
  290. package/scripts/skill-quality-tracker.js +284 -0
  291. package/scripts/slo-alert-engine.js +14 -0
  292. package/scripts/slow-loop.js +72 -0
  293. package/scripts/social-analytics/db/schema.sql +32 -0
  294. package/scripts/social-analytics/digest.js +256 -0
  295. package/scripts/social-analytics/generate-instagram-card.js +97 -0
  296. package/scripts/social-analytics/instagram-thumbgate-post.js +73 -0
  297. package/scripts/social-analytics/mcp-server.js +289 -0
  298. package/scripts/social-analytics/normalizer.js +580 -0
  299. package/scripts/social-analytics/notify.js +162 -0
  300. package/scripts/social-analytics/poll-all.js +107 -0
  301. package/scripts/social-analytics/pollers/github.js +195 -0
  302. package/scripts/social-analytics/pollers/instagram.js +253 -0
  303. package/scripts/social-analytics/pollers/linkedin.js +330 -0
  304. package/scripts/social-analytics/pollers/plausible.js +247 -0
  305. package/scripts/social-analytics/pollers/reddit.js +306 -0
  306. package/scripts/social-analytics/pollers/threads.js +233 -0
  307. package/scripts/social-analytics/pollers/tiktok.js +203 -0
  308. package/scripts/social-analytics/pollers/x.js +227 -0
  309. package/scripts/social-analytics/pollers/youtube.js +304 -0
  310. package/scripts/social-analytics/pollers/zernio.js +180 -0
  311. package/scripts/social-analytics/publish-instagram-thumbgate.js +85 -0
  312. package/scripts/social-analytics/publishers/devto.js +122 -0
  313. package/scripts/social-analytics/publishers/instagram.js +317 -0
  314. package/scripts/social-analytics/publishers/linkedin.js +294 -0
  315. package/scripts/social-analytics/publishers/reddit.js +390 -0
  316. package/scripts/social-analytics/publishers/threads.js +275 -0
  317. package/scripts/social-analytics/publishers/tiktok.js +217 -0
  318. package/scripts/social-analytics/publishers/x.js +259 -0
  319. package/scripts/social-analytics/publishers/youtube.js +223 -0
  320. package/scripts/social-analytics/publishers/zernio.js +209 -0
  321. package/scripts/social-analytics/run-digest.js +34 -0
  322. package/scripts/social-analytics/store.js +257 -0
  323. package/scripts/social-analytics/utm.js +143 -0
  324. package/scripts/social-pipeline.js +2628 -0
  325. package/scripts/social-quality-gate.js +18 -0
  326. package/scripts/social-reply-monitor.js +445 -0
  327. package/scripts/status-dashboard.js +155 -0
  328. package/scripts/statusline-lesson.js +16 -0
  329. package/scripts/statusline-tower.js +8 -0
  330. package/scripts/statusline.sh +116 -0
  331. package/scripts/stripe-live-status.js +115 -0
  332. package/scripts/subagent-profiles.js +79 -0
  333. package/scripts/sync-gh-secrets-from-env.sh +70 -0
  334. package/scripts/sync-github-about.js +52 -0
  335. package/scripts/sync-version.js +451 -0
  336. package/scripts/synthetic-dpo.js +234 -0
  337. package/scripts/telemetry-analytics.js +821 -0
  338. package/scripts/tessl-export.js +371 -0
  339. package/scripts/test-coverage.js +120 -0
  340. package/scripts/thompson-sampling.js +417 -0
  341. package/scripts/thumbgate-search.js +189 -0
  342. package/scripts/tool-kpi-tracker.js +12 -0
  343. package/scripts/tool-registry.js +811 -0
  344. package/scripts/train_from_feedback.py +910 -0
  345. package/scripts/user-profile.js +78 -0
  346. package/scripts/validate-feedback.js +580 -0
  347. package/scripts/validate-workflow-contract.js +287 -0
  348. package/scripts/vector-store.js +198 -0
  349. package/scripts/verification-loop.js +291 -0
  350. package/scripts/verify-obsidian-setup.sh +269 -0
  351. package/scripts/verify-run.js +269 -0
  352. package/scripts/webhook-delivery.js +62 -0
  353. package/scripts/weekly-auto-post.js +124 -0
  354. package/scripts/workflow-runs.js +154 -0
  355. package/scripts/workflow-sprint-intake.js +475 -0
  356. package/scripts/workspace-evolver.js +374 -0
  357. package/scripts/x-autonomous-marketing.js +139 -0
  358. package/scripts/xmemory-lite.js +405 -0
  359. package/skills/agent-memory/SKILL.md +97 -0
  360. package/skills/solve-architecture-autonomy/SKILL.md +17 -0
  361. package/skills/solve-architecture-autonomy/tool.js +33 -0
  362. package/skills/thumbgate/SKILL.md +114 -0
  363. package/skills/thumbgate-feedback/SKILL.md +49 -0
  364. package/src/api/server.js +4208 -0
@@ -0,0 +1,237 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Background Agent Governance — the missing layer for Ramp/Ona-style agent stacks.
6
+ *
7
+ * Background agents run unattended (writing 57% of PRs at Ramp). They need:
8
+ * 1. Run tracking — what did each agent run do?
9
+ * 2. Governance gate — should this PR/action be allowed based on past failures?
10
+ * 3. Post-run audit — auto-capture feedback from CI results
11
+ * 4. Governance report — "X runs, Y blocked, Z lessons learned"
12
+ *
13
+ * Integrates with: MCP server, gates engine, org dashboard, lesson inference.
14
+ */
15
+
16
+ const fs = require('fs');
17
+ const path = require('path');
18
+ const { resolveFeedbackDir } = require('./feedback-paths');
19
+
20
+ const RUNS_FILE = 'agent-runs.jsonl';
21
+
22
+ function getFeedbackDir() { return resolveFeedbackDir(); }
23
+ function getRunsPath() { return path.join(getFeedbackDir(), RUNS_FILE); }
24
+
25
+ function readJsonl(fp) {
26
+ if (!fs.existsSync(fp)) return [];
27
+ const raw = fs.readFileSync(fp, 'utf-8').trim();
28
+ if (!raw) return [];
29
+ return raw.split('\n').map((l) => { try { return JSON.parse(l); } catch { return null; } }).filter(Boolean);
30
+ }
31
+
32
+ function ensureDir(fp) { const d = path.dirname(fp); if (!fs.existsSync(d)) fs.mkdirSync(d, { recursive: true }); }
33
+
34
+ // ---------------------------------------------------------------------------
35
+ // 1. Run Tracking
36
+ // ---------------------------------------------------------------------------
37
+
38
+ /**
39
+ * Record a background agent run.
40
+ * Called when a background agent starts or completes a task.
41
+ */
42
+ function recordAgentRun({ agentId, runType, source, branch, prNumber, status, gatesChecked, gatesBlocked, filesChanged, ciPassed, duration, metadata } = {}) {
43
+ const runsPath = getRunsPath();
44
+ ensureDir(runsPath);
45
+ const run = {
46
+ id: `run_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
47
+ timestamp: new Date().toISOString(),
48
+ agentId: agentId || 'unknown',
49
+ runType: runType || 'unknown', // 'pr', 'fix', 'refactor', 'ci-repair', 'migration'
50
+ source: source || 'background', // 'background', 'triggered', 'scheduled', 'manual'
51
+ branch: branch || null,
52
+ prNumber: prNumber || null,
53
+ status: status || 'started', // 'started', 'completed', 'blocked', 'failed'
54
+ gatesChecked: gatesChecked || 0,
55
+ gatesBlocked: gatesBlocked || 0,
56
+ filesChanged: filesChanged || 0,
57
+ ciPassed: ciPassed === undefined ? null : ciPassed,
58
+ durationMs: duration || null,
59
+ metadata: metadata || {},
60
+ };
61
+ fs.appendFileSync(runsPath, JSON.stringify(run) + '\n');
62
+ return run;
63
+ }
64
+
65
+ // ---------------------------------------------------------------------------
66
+ // 2. Governance Gate — pre-run check
67
+ // ---------------------------------------------------------------------------
68
+
69
+ /**
70
+ * Check if a background agent run should proceed based on governance rules.
71
+ * Returns { allowed, blockers, warnings, governanceScore }.
72
+ */
73
+ function checkRunGovernance({ agentId, runType, branch, filesChanged } = {}) {
74
+ const runs = readJsonl(getRunsPath());
75
+ const blockers = [];
76
+ const warnings = [];
77
+
78
+ // Rule 1: Block if this agent has > 50% failure rate in last 10 runs
79
+ const agentRuns = runs.filter((r) => r.agentId === agentId).slice(-10);
80
+ const failedRuns = agentRuns.filter((r) => r.status === 'failed' || r.status === 'blocked');
81
+ if (agentRuns.length >= 5 && failedRuns.length / agentRuns.length > 0.5) {
82
+ blockers.push({ rule: 'high_failure_rate', message: `Agent ${agentId} has ${failedRuns.length}/${agentRuns.length} failed runs (>50%)`, severity: 'critical' });
83
+ }
84
+
85
+ // Rule 2: Warn if agent has been blocked by gates in recent runs
86
+ const recentBlocked = agentRuns.filter((r) => r.gatesBlocked > 0);
87
+ if (recentBlocked.length >= 3) {
88
+ warnings.push({ rule: 'repeated_gate_blocks', message: `Agent ${agentId} has been gate-blocked in ${recentBlocked.length} recent runs`, severity: 'warning' });
89
+ }
90
+
91
+ // Rule 3: Block if targeting protected branch without CI passing
92
+ if (branch && /^(main|master|develop)$/.test(branch)) {
93
+ warnings.push({ rule: 'protected_branch', message: `Run targets protected branch "${branch}" — CI must pass before merge`, severity: 'warning' });
94
+ }
95
+
96
+ // Rule 4: Warn if too many files changed (large blast radius)
97
+ if (filesChanged > 20) {
98
+ warnings.push({ rule: 'large_blast_radius', message: `${filesChanged} files changed — consider splitting into smaller PRs`, severity: 'warning' });
99
+ }
100
+
101
+ const governanceScore = Math.max(0, 100 - blockers.length * 40 - warnings.length * 10);
102
+
103
+ return {
104
+ allowed: blockers.length === 0,
105
+ blockers,
106
+ warnings,
107
+ governanceScore,
108
+ checkedAt: new Date().toISOString(),
109
+ };
110
+ }
111
+
112
+ // ---------------------------------------------------------------------------
113
+ // 3. Post-Run Audit — auto-capture feedback from CI
114
+ // ---------------------------------------------------------------------------
115
+
116
+ /**
117
+ * Auto-capture feedback from a completed background agent run.
118
+ * Converts CI pass/fail into structured feedback for the learning loop.
119
+ */
120
+ function auditCompletedRun({ runId, agentId, ciPassed, ciOutput, prNumber, branch, filesChanged } = {}) {
121
+ const signal = ciPassed ? 'positive' : 'negative';
122
+ const context = ciPassed
123
+ ? `Background agent run ${runId || 'unknown'} completed successfully. PR #${prNumber || '?'} on ${branch || '?'}. ${filesChanged || 0} files changed. CI passed.`
124
+ : `Background agent run ${runId || 'unknown'} failed. PR #${prNumber || '?'} on ${branch || '?'}. ${filesChanged || 0} files changed. CI failed.`;
125
+
126
+ const whatWentWrong = !ciPassed && ciOutput ? ciOutput.slice(0, 500) : null;
127
+
128
+ // Record the completed run
129
+ const run = recordAgentRun({
130
+ agentId,
131
+ runType: 'pr',
132
+ source: 'background',
133
+ branch,
134
+ prNumber,
135
+ status: ciPassed ? 'completed' : 'failed',
136
+ filesChanged,
137
+ ciPassed,
138
+ });
139
+
140
+ // Auto-capture feedback
141
+ let feedbackResult = null;
142
+ try {
143
+ const { captureFeedback } = require('./feedback-loop');
144
+ feedbackResult = captureFeedback({
145
+ signal: ciPassed ? 'up' : 'down',
146
+ context,
147
+ whatWentWrong,
148
+ whatWorked: ciPassed ? `Agent successfully completed PR #${prNumber || '?'}` : undefined,
149
+ tags: ['background-agent', ciPassed ? 'ci-pass' : 'ci-fail', `agent:${agentId || 'unknown'}`],
150
+ });
151
+ } catch { /* feedback capture is non-critical */ }
152
+
153
+ return { run, feedbackResult, signal, context };
154
+ }
155
+
156
+ // ---------------------------------------------------------------------------
157
+ // 4. Governance Report
158
+ // ---------------------------------------------------------------------------
159
+
160
+ /**
161
+ * Generate a governance report for background agent runs.
162
+ * Shows: total runs, blocked, pass rate, top failing agents, lessons learned.
163
+ */
164
+ function generateGovernanceReport({ periodHours = 24 } = {}) {
165
+ const runs = readJsonl(getRunsPath());
166
+ const cutoff = Date.now() - periodHours * 60 * 60 * 1000;
167
+ const recent = runs.filter((r) => new Date(r.timestamp).getTime() > cutoff);
168
+
169
+ const total = recent.length;
170
+ const completed = recent.filter((r) => r.status === 'completed').length;
171
+ const failed = recent.filter((r) => r.status === 'failed').length;
172
+ const blocked = recent.filter((r) => r.status === 'blocked').length;
173
+ const started = recent.filter((r) => r.status === 'started').length;
174
+
175
+ const passRate = (completed + failed) > 0 ? Math.round((completed / (completed + failed)) * 1000) / 10 : 0;
176
+ const totalGatesChecked = recent.reduce((s, r) => s + (r.gatesChecked || 0), 0);
177
+ const totalGatesBlocked = recent.reduce((s, r) => s + (r.gatesBlocked || 0), 0);
178
+
179
+ // Per-agent breakdown
180
+ const byAgent = {};
181
+ for (const r of recent) {
182
+ if (!byAgent[r.agentId]) byAgent[r.agentId] = { completed: 0, failed: 0, blocked: 0, total: 0 };
183
+ byAgent[r.agentId].total++;
184
+ if (r.status === 'completed') byAgent[r.agentId].completed++;
185
+ if (r.status === 'failed') byAgent[r.agentId].failed++;
186
+ if (r.status === 'blocked') byAgent[r.agentId].blocked++;
187
+ }
188
+
189
+ const agentSummaries = Object.entries(byAgent).map(([id, counts]) => ({
190
+ agentId: id,
191
+ ...counts,
192
+ passRate: (counts.completed + counts.failed) > 0 ? Math.round((counts.completed / (counts.completed + counts.failed)) * 1000) / 10 : 0,
193
+ })).sort((a, b) => a.passRate - b.passRate);
194
+
195
+ // By run type
196
+ const byType = {};
197
+ for (const r of recent) {
198
+ if (!byType[r.runType]) byType[r.runType] = 0;
199
+ byType[r.runType]++;
200
+ }
201
+
202
+ return {
203
+ periodHours,
204
+ total, completed, failed, blocked, started,
205
+ passRate,
206
+ gatesChecked: totalGatesChecked,
207
+ gatesBlocked: totalGatesBlocked,
208
+ agents: agentSummaries,
209
+ topFailingAgent: agentSummaries.length > 0 && agentSummaries[0].passRate < 80 ? agentSummaries[0] : null,
210
+ byType,
211
+ generatedAt: new Date().toISOString(),
212
+ };
213
+ }
214
+
215
+ /**
216
+ * Format governance report as a human-readable string.
217
+ */
218
+ function formatGovernanceReport(report) {
219
+ const lines = [
220
+ `Background Agent Governance Report (${report.periodHours}h)`,
221
+ `Total runs: ${report.total} | Completed: ${report.completed} | Failed: ${report.failed} | Blocked: ${report.blocked}`,
222
+ `Pass rate: ${report.passRate}%`,
223
+ `Gates checked: ${report.gatesChecked} | Gates blocked: ${report.gatesBlocked}`,
224
+ ];
225
+ if (report.topFailingAgent) {
226
+ lines.push(`Top failing agent: ${report.topFailingAgent.agentId} (${report.topFailingAgent.passRate}% pass rate)`);
227
+ }
228
+ if (Object.keys(report.byType).length > 0) {
229
+ lines.push(`Run types: ${Object.entries(report.byType).map(([t, c]) => `${t}:${c}`).join(', ')}`);
230
+ }
231
+ return lines.join('\n');
232
+ }
233
+
234
+ module.exports = {
235
+ recordAgentRun, checkRunGovernance, auditCompletedRun,
236
+ generateGovernanceReport, formatGovernanceReport, getRunsPath,
237
+ };
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * behavioral-extraction.js
4
+ *
5
+ * Layer 4: Behavioral Learning
6
+ * Extracts user preference patterns from feedback logs to adjust agent approach.
7
+ */
8
+
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+
12
+ const HOME = process.env.HOME || process.env.USERPROFILE || '';
13
+ const envDir = process.env.THUMBGATE_FEEDBACK_DIR;
14
+ const localFallback = path.join(process.cwd(), '.thumbgate');
15
+ const localClaude = path.join(process.cwd(), '.claude', 'memory', 'feedback');
16
+ const baseDir = envDir || (fs.existsSync(localFallback) ? localFallback : localClaude);
17
+
18
+ const FEEDBACK_LOG_PATH = path.join(baseDir, 'feedback-log.jsonl');
19
+ const TRAITS_PATH = path.join(baseDir, 'behavioral-traits.json');
20
+
21
+ const TRAIT_DEFINITIONS = [
22
+ {
23
+ id: 'surgical-over-rewrite',
24
+ patterns: [/surgical/i, /targeted/i, /don't rewrite/i, /minimal change/i],
25
+ threshold: 2,
26
+ description: 'User prefers surgical edits over full file rewrites.'
27
+ },
28
+ {
29
+ id: 'concise-over-verbose',
30
+ patterns: [/concise/i, /short/i, /less talk/i, /too much chat/i],
31
+ threshold: 2,
32
+ description: 'User prefers concise, direct communication.'
33
+ },
34
+ {
35
+ id: 'test-driven',
36
+ patterns: [/test first/i, /where is the test/i, /run tests/i, /tdd/i],
37
+ threshold: 2,
38
+ description: 'User prioritizes test coverage and verification.'
39
+ }
40
+ ];
41
+
42
+ function extractTraits() {
43
+ if (!fs.existsSync(FEEDBACK_LOG_PATH)) {
44
+ console.log('No feedback log found at', FEEDBACK_LOG_PATH);
45
+ return [];
46
+ }
47
+
48
+ const logLines = fs.readFileSync(FEEDBACK_LOG_PATH, 'utf-8').split('\n').filter(Boolean);
49
+ const evidenceCount = {};
50
+
51
+ logLines.forEach(line => {
52
+ try {
53
+ const entry = JSON.parse(line);
54
+ const text = `${entry.context || ''} ${entry.whatWorked || ''} ${entry.whatWentWrong || ''} ${entry.whatToChange || ''}`;
55
+
56
+ TRAIT_DEFINITIONS.forEach(trait => {
57
+ if (trait.patterns.some(p => p.test(text))) {
58
+ evidenceCount[trait.id] = (evidenceCount[trait.id] || 0) + 1;
59
+ }
60
+ });
61
+ } catch (e) {
62
+ // skip malformed lines
63
+ }
64
+ });
65
+
66
+ const activeTraits = TRAIT_DEFINITIONS
67
+ .filter(trait => (evidenceCount[trait.id] || 0) >= trait.threshold)
68
+ .map(trait => ({
69
+ id: trait.id,
70
+ description: trait.description,
71
+ evidenceCount: evidenceCount[trait.id]
72
+ }));
73
+
74
+ return activeTraits;
75
+ }
76
+
77
+ function run() {
78
+ console.log('🤖 [Layer 4] Extracting behavioral patterns...');
79
+ const traits = extractTraits();
80
+
81
+ if (traits.length > 0) {
82
+ fs.writeFileSync(TRAITS_PATH, JSON.stringify({
83
+ generatedAt: new Date().toISOString(),
84
+ traits
85
+ }, null, 2));
86
+ console.log(`✅ Extracted ${traits.length} behavioral traits.`);
87
+ traits.forEach(t => console.log(` - ${t.id} (${t.evidenceCount} evidences)`));
88
+ } else {
89
+ console.log('No strong behavioral patterns identified yet.');
90
+ }
91
+ }
92
+
93
+ if (require.main === module) {
94
+ run();
95
+ }
96
+
97
+ module.exports = { extractTraits };
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Bayesian Belief Update Engine
4
+ *
5
+ * Implements belief revision using recursive Bayesian updates.
6
+ * Updates priorProbability and uncertainty based on new observations.
7
+ * Handles entropy-based pruning of low-confidence memories.
8
+ */
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+
13
+ /**
14
+ * Perform a Bayesian update on a belief.
15
+ * @param {object} belief - The existing bayesian metadata
16
+ * @param {number} likelihood - The likelihood of the new observation (0-1)
17
+ * @returns {object} Updated bayesian metadata
18
+ */
19
+ function updateBelief(belief, likelihood) {
20
+ const prior = belief.priorProbability;
21
+ const n = belief.observations;
22
+
23
+ // Simple Bayesian update for probability (weighted mean)
24
+ // P(H|E) = (P(E|H) * P(H)) / P(E)
25
+ // Here we use a simpler recursive update for multi-turn interaction
26
+ const newPrior = (prior * n + likelihood) / (n + 1);
27
+
28
+ // Sentry fix: Contradiction should be based on raw difference between likelihood and prior
29
+ // to ensure strong contradictions increase uncertainty regardless of n.
30
+ const contradiction = Math.abs(likelihood - prior);
31
+ const newUncertainty = (belief.uncertainty * n + contradiction) / (n + 1);
32
+
33
+ return {
34
+ priorProbability: Math.round(newPrior * 1000) / 1000,
35
+ uncertainty: Math.round(newUncertainty * 1000) / 1000,
36
+ observations: n + 1,
37
+ lastUpdated: new Date().toISOString(),
38
+ };
39
+ }
40
+
41
+ /**
42
+ * Check if a memory should be pruned based on entropy.
43
+ * @param {object} bayesian - Bayesian metadata
44
+ * @returns {boolean} True if memory should be pruned
45
+ */
46
+ function shouldPrune(bayesian) {
47
+ const ENTROPY_THRESHOLD = 0.7;
48
+ const OBSERVATION_FLOOR = 3;
49
+
50
+ // Prune if high uncertainty after enough observations
51
+ if (bayesian.observations >= OBSERVATION_FLOOR && bayesian.uncertainty > ENTROPY_THRESHOLD) {
52
+ return true;
53
+ }
54
+
55
+ // Prune if prior probability falls too low (it's likely a false belief)
56
+ if (bayesian.priorProbability < 0.2) {
57
+ return true;
58
+ }
59
+
60
+ return false;
61
+ }
62
+
63
+ module.exports = {
64
+ updateBelief,
65
+ shouldPrune,
66
+ };
67
+
68
+ if (require.main === module) {
69
+ // Unit test logic if run directly
70
+ console.log('Testing Bayesian Update...');
71
+ let belief = { priorProbability: 0.5, uncertainty: 0.5, observations: 1 };
72
+
73
+ // Sequence of positive signals
74
+ belief = updateBelief(belief, 0.9);
75
+ console.log('Update 1 (Success):', belief);
76
+ belief = updateBelief(belief, 0.95);
77
+ console.log('Update 2 (Success):', belief);
78
+
79
+ // Contradiction
80
+ belief = updateBelief(belief, 0.1);
81
+ console.log('Update 3 (Contradiction):', belief);
82
+
83
+ console.log('Should prune?', shouldPrune(belief));
84
+ }