thumbgate 1.0.0 → 1.1.0

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thumbgate",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "plugins": [
5
5
  {
6
6
  "name": "thumbgate",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "thumbgate",
3
3
  "description": "Pre-action gates that block AI coding agents from repeating known mistakes. Captures feedback, auto-promotes failures into prevention rules, and enforces them via PreToolUse hooks.",
4
- "version": "1.0.0",
4
+ "version": "1.1.0",
5
5
  "author": {
6
6
  "name": "Igor Ganapolsky"
7
7
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thumbgate",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "ThumbGate — 👍👎 feedback that teaches your AI agent. Thumbs down a mistake, it never happens again.",
5
5
  "homepage": "https://github.com/IgorGanapolsky/thumbgate",
6
6
  "transport": "stdio",
@@ -3,7 +3,7 @@
3
3
  - `chatgpt/openapi.yaml`: import into GPT Actions.
4
4
  - `gemini/function-declarations.json`: Gemini function-calling definitions.
5
5
  - `mcp/server-stdio.js`: underlying local MCP stdio server implementation.
6
- - `claude/.mcp.json`: example Claude Code MCP config using `npx --yes --package thumbgate@1.0.0 thumbgate serve`.
6
+ - `claude/.mcp.json`: example Claude Code MCP config using `npx --yes --package thumbgate@1.1.0 thumbgate serve`.
7
7
  - `codex/config.toml`: example Codex MCP profile section using the same version-pinned portable launcher.
8
8
  - `amp/skills/thumbgate-feedback/SKILL.md`: Amp skill template.
9
9
  - `opencode/opencode.json`: portable OpenCode MCP profile using the same version-pinned portable launcher.
@@ -2,13 +2,13 @@
2
2
  "mcpServers": {
3
3
  "thumbgate": {
4
4
  "command": "npx",
5
- "args": ["--yes", "--package", "thumbgate@1.0.0", "thumbgate", "serve"]
5
+ "args": ["--yes", "--package", "thumbgate@1.1.0", "thumbgate", "serve"]
6
6
  }
7
7
  },
8
8
  "hooks": {
9
9
  "preToolUse": {
10
10
  "command": "npx",
11
- "args": ["--yes", "--package", "thumbgate@1.0.0", "thumbgate", "gate-check"]
11
+ "args": ["--yes", "--package", "thumbgate@1.1.0", "thumbgate", "gate-check"]
12
12
  }
13
13
  }
14
14
  }
@@ -1,9 +1,9 @@
1
1
  # Codex MCP profile (copy into ~/.codex/config.toml or merge section)
2
2
  [mcp_servers.thumbgate]
3
3
  command = "npx"
4
- args = ["--yes", "--package", "thumbgate@1.0.0", "thumbgate", "serve"]
4
+ args = ["--yes", "--package", "thumbgate@1.1.0", "thumbgate", "serve"]
5
5
 
6
6
  # Hard PreToolUse hook for Codex
7
7
  [hooks.pre_tool_use]
8
8
  command = "npx"
9
- args = ["--yes", "--package", "thumbgate@1.0.0", "thumbgate", "gate-check"]
9
+ args = ["--yes", "--package", "thumbgate@1.1.0", "thumbgate", "gate-check"]
@@ -97,6 +97,7 @@ const {
97
97
  assembleUnifiedContext,
98
98
  formatUnifiedContext,
99
99
  } = require('../../scripts/context-manager');
100
+ const { exportHfDataset } = require('../../scripts/export-hf-dataset');
100
101
 
101
102
  const PRO_CHECKOUT_URL = 'https://thumbgate-production.up.railway.app/checkout/pro';
102
103
 
@@ -118,7 +119,7 @@ const {
118
119
  finalizeSession: finalizeFeedbackSession,
119
120
  } = require('../../scripts/feedback-session');
120
121
 
121
- const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.0.0' };
122
+ const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.1.0' };
122
123
  const COMMERCE_CATEGORIES = [
123
124
  'product_recommendation',
124
125
  'brand_compliance',
@@ -493,6 +494,14 @@ async function callToolInner(name, args) {
493
494
  case 'export_dpo_pairs':
494
495
  enforceLimit('export_dpo');
495
496
  return buildExportDpoResponse(args);
497
+ case 'export_hf_dataset': {
498
+ enforceLimit('export_dpo');
499
+ const outputDir = args.outputDir ? resolveSafePath(args.outputDir) : undefined;
500
+ return toTextResult(exportHfDataset({
501
+ outputDir,
502
+ includeProvenance: args.includeProvenance !== false,
503
+ }));
504
+ }
496
505
  case 'export_databricks_bundle': {
497
506
  enforceLimit('export_databricks');
498
507
  const outputPath = args.outputPath ? resolveSafePath(args.outputPath) : undefined;
@@ -7,7 +7,7 @@
7
7
  "npx",
8
8
  "--yes",
9
9
  "--package",
10
- "thumbgate@1.0.0",
10
+ "thumbgate@1.1.0",
11
11
  "thumbgate",
12
12
  "serve"
13
13
  ],
@@ -22,6 +22,7 @@
22
22
  "bootstrap_internal_agent",
23
23
  "prevention_rules",
24
24
  "export_dpo_pairs",
25
+ "export_hf_dataset",
25
26
  "export_databricks_bundle",
26
27
  "construct_context_pack",
27
28
  "evaluate_context_pack",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thumbgate",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "ThumbGate — Make your AI coding agent self-improving. Every mistake becomes a prevention rule that physically blocks the agent from repeating it. Feedback-driven enforcement via PreToolUse hooks, Thompson Sampling for adaptive gates, SQLite+FTS5 lesson DB, and LanceDB vector search. Your agent gets smarter with every session.",
5
5
  "homepage": "https://thumbgate-production.up.railway.app",
6
6
  "repository": {
@@ -66,7 +66,7 @@
66
66
  "social:post-everywhere:dry": "node scripts/post-everywhere.js --dry-run",
67
67
  "social:reply-monitor": "node scripts/social-reply-monitor.js",
68
68
  "social:reply-monitor:dry": "node scripts/social-reply-monitor.js --dry-run",
69
- "test": "npm run test:schema && npm run test:loop && npm run test:dpo && npm run test:kto && npm run test:api && npm run test:proof && npm run test:e2e && npm run test:rlaif && npm run test:attribution && npm run test:quality && npm run test:intelligence && npm run test:training-export && npm run test:deployment && npm run test:operational-integrity && npm run test:workflow && npm run test:billing && npm run test:cli && npm run test:watcher && npm run test:autoresearch && npm run test:ops && npm run test:tessl && npm run test:gates && npm run test:evoskill && npm run test:gates-hardening && npm run test:workers && npm run test:social-analytics && npm run test:memalign && npm run test:xmemory-lite && npm run test:filesystem-search && npm run test:zernio && npm run test:obsidian-export && npm run test:lesson-db && npm run test:lesson-rotation && npm run test:memory-dedup && npm run test:feedback-quality && npm run test:sync-version && npm run test:check-congruence && npm run test:tool-registry && npm run test:feedback-to-rules && npm run test:memory-firewall && npm run test:belief-update && npm run test:hosted-config && npm run test:cloudflare-sandbox && npm run test:mcp-config && npm run test:plan-gate && npm run test:pulse && npm run test:semantic-layer && npm run test:data-pipeline && npm run test:optimize-context && npm run test:principle-extractor && npm run test:analytics-window && npm run test:funnel-analytics && npm run test:experiment-tracker && npm run test:build-metadata && npm run test:context-engine && npm run test:hf-papers && npm run test:marketing-experiment && npm run test:seo-gsd && npm run test:verify-run && npm run test:export-dpo-pairs && npm run test:license && npm run test:bot-detector && npm run test:postinstall && npm run test:funnel-invariants && npm run test:cli-telemetry && npm run test:pro-parity && npm run test:model-tier-router && npm run test:computer-use-firewall && npm run test:skill-exporter && npm run test:statusline && npm run test:evolution && npm run test:org-dashboard && npm run test:multi-hop-recall && npm run test:synthetic-dpo && npm run test:thumbgate-skill && npm run test:learn-hub && npm run test:feedback-fallback && npm run test:metaclaw && npm run test:server-lock && npm run test:control-tower && npm run test:pii-scanner && npm run test:data-governance && npm run test:lesson-inference && npm run test:lesson-retrieval && npm run test:reflector-agent && npm run test:feedback-session && npm run test:feedback-history-distiller && npm run test:hallucination-detector && npm run test:history-distiller && npm run test:predictive-insights && npm run test:prove-predictive-insights && npm run test:statusbar-cli && npm run test:generate-instagram-card && npm run test:instagram-thumbgate-post && npm run test:publish-instagram-thumbgate && npm run test:lesson-synthesis && npm run test:background-governance && npm run test:memory-migration && npm run test:prompt-dlp && npm run test:ephemeral-store && npm run test:agent-security && npm run test:skill-progressive && npm run test:per-step-scoring && npm run test:weekly-auto-post && npm run test:social-quality-gate && npm run test:a2ui-engine && npm run test:gate-satisfy && npm run test:money-watcher && npm run test:utm && npm run test:product-feedback && npm run test:feedback-root-consolidator && npm run test:engagement-audit && npm run test:install-growth-automation && npm run test:publish-thumbgate-launch && npm run test:reconcile-thumbgate-campaign && npm run test:reddit-publisher && npm run test:schedule-thumbgate-campaign && npm run test:social-reply-monitor && npm run test:sync-launch-assets",
69
+ "test": "npm run test:schema && npm run test:loop && npm run test:dpo && npm run test:kto && npm run test:api && npm run test:proof && npm run test:e2e && npm run test:rlaif && npm run test:attribution && npm run test:quality && npm run test:intelligence && npm run test:training-export && npm run test:deployment && npm run test:operational-integrity && npm run test:workflow && npm run test:billing && npm run test:cli && npm run test:watcher && npm run test:autoresearch && npm run test:ops && npm run test:tessl && npm run test:gates && npm run test:evoskill && npm run test:gates-hardening && npm run test:workers && npm run test:social-analytics && npm run test:memalign && npm run test:xmemory-lite && npm run test:filesystem-search && npm run test:zernio && npm run test:obsidian-export && npm run test:lesson-db && npm run test:lesson-rotation && npm run test:memory-dedup && npm run test:feedback-quality && npm run test:sync-version && npm run test:check-congruence && npm run test:tool-registry && npm run test:feedback-to-rules && npm run test:memory-firewall && npm run test:belief-update && npm run test:hosted-config && npm run test:cloudflare-sandbox && npm run test:mcp-config && npm run test:plan-gate && npm run test:pulse && npm run test:semantic-layer && npm run test:data-pipeline && npm run test:optimize-context && npm run test:principle-extractor && npm run test:analytics-window && npm run test:funnel-analytics && npm run test:experiment-tracker && npm run test:build-metadata && npm run test:context-engine && npm run test:hf-papers && npm run test:marketing-experiment && npm run test:seo-gsd && npm run test:verify-run && npm run test:export-dpo-pairs && npm run test:export-hf-dataset && npm run test:license && npm run test:bot-detector && npm run test:postinstall && npm run test:funnel-invariants && npm run test:cli-telemetry && npm run test:pro-parity && npm run test:model-tier-router && npm run test:computer-use-firewall && npm run test:skill-exporter && npm run test:statusline && npm run test:evolution && npm run test:org-dashboard && npm run test:multi-hop-recall && npm run test:synthetic-dpo && npm run test:thumbgate-skill && npm run test:learn-hub && npm run test:feedback-fallback && npm run test:metaclaw && npm run test:server-lock && npm run test:control-tower && npm run test:pii-scanner && npm run test:data-governance && npm run test:lesson-inference && npm run test:lesson-retrieval && npm run test:reflector-agent && npm run test:feedback-session && npm run test:feedback-history-distiller && npm run test:hallucination-detector && npm run test:history-distiller && npm run test:predictive-insights && npm run test:prove-predictive-insights && npm run test:statusbar-cli && npm run test:generate-instagram-card && npm run test:instagram-thumbgate-post && npm run test:publish-instagram-thumbgate && npm run test:lesson-synthesis && npm run test:background-governance && npm run test:memory-migration && npm run test:prompt-dlp && npm run test:ephemeral-store && npm run test:agent-security && npm run test:skill-progressive && npm run test:per-step-scoring && npm run test:weekly-auto-post && npm run test:social-quality-gate && npm run test:a2ui-engine && npm run test:gate-satisfy && npm run test:money-watcher && npm run test:utm && npm run test:product-feedback && npm run test:feedback-root-consolidator && npm run test:engagement-audit && npm run test:install-growth-automation && npm run test:publish-thumbgate-launch && npm run test:reconcile-thumbgate-campaign && npm run test:reddit-publisher && npm run test:schedule-thumbgate-campaign && npm run test:social-reply-monitor && npm run test:sync-launch-assets",
70
70
  "test:feedback-fallback": "node --test tests/feedback-fallback.test.js",
71
71
  "test:metaclaw": "node --test tests/metaclaw-features.test.js",
72
72
  "test:server-lock": "node --test tests/server-stdio-lock.test.js",
@@ -105,6 +105,8 @@
105
105
  "test:seo-gsd": "node --test tests/seo-gsd.test.js",
106
106
  "test:verify-run": "node --test tests/verify-run.test.js",
107
107
  "test:export-dpo-pairs": "node --test tests/export-dpo-pairs.test.js",
108
+ "test:export-hf-dataset": "node --test tests/export-hf-dataset.test.js",
109
+ "export:hf": "node scripts/export-hf-dataset.js",
108
110
  "seo:gsd": "node scripts/seo-gsd.js plan",
109
111
  "seo:gsd:write": "node scripts/seo-gsd.js plan --write",
110
112
  "test:congruence": "node scripts/check-congruence.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-bridge",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Run Codex review, adversarial review, and second-pass handoffs from Claude Code while keeping ThumbGate reliability memory in the loop.",
5
5
  "author": {
6
6
  "name": "Igor Ganapolsky",
@@ -5,7 +5,7 @@
5
5
  "args": [
6
6
  "--yes",
7
7
  "--package",
8
- "thumbgate@1.0.0",
8
+ "thumbgate@1.1.0",
9
9
  "thumbgate",
10
10
  "serve"
11
11
  ]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-profile",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "ThumbGate for Codex: pre-action gates, skill packs, hallucination detection, PII scanning, progressive disclosure (82% token savings), and MCP-backed reliability memory.",
5
5
  "author": {
6
6
  "name": "Igor Ganapolsky",
@@ -5,7 +5,7 @@
5
5
  "args": [
6
6
  "--yes",
7
7
  "--package",
8
- "thumbgate@1.0.0",
8
+ "thumbgate@1.1.0",
9
9
  "thumbgate",
10
10
  "serve"
11
11
  ]
@@ -31,7 +31,7 @@ The following block is appended to `~/.codex/config.toml`:
31
31
  ```toml
32
32
  [mcp_servers.thumbgate]
33
33
  command = "npx"
34
- args = ["--yes", "--package", "thumbgate@1.0.0", "thumbgate", "serve"]
34
+ args = ["--yes", "--package", "thumbgate@1.1.0", "thumbgate", "serve"]
35
35
  ```
36
36
 
37
37
  The repo-local Codex app plugin ships the same runtime path through `plugins/codex-profile/.mcp.json`, so the manual config and plugin metadata stay aligned.
@@ -29,7 +29,7 @@ That profile launches:
29
29
  ```toml
30
30
  [mcp_servers.thumbgate]
31
31
  command = "npx"
32
- args = ["--yes", "--package", "thumbgate@1.0.0", "thumbgate", "serve"]
32
+ args = ["--yes", "--package", "thumbgate@1.1.0", "thumbgate", "serve"]
33
33
  ```
34
34
 
35
35
  ## Why this exists
@@ -2,7 +2,7 @@
2
2
  "name": "thumbgate",
3
3
  "displayName": "ThumbGate",
4
4
  "description": "👍👎 Thumbs down a mistake — your AI agent won't repeat it. Thumbs up good work — it remembers the pattern.",
5
- "version": "1.0.0",
5
+ "version": "1.1.0",
6
6
  "author": {
7
7
  "name": "Igor Ganapolsky"
8
8
  },
@@ -25,7 +25,7 @@ The portable profile adds this MCP server entry:
25
25
  "mcp": {
26
26
  "thumbgate": {
27
27
  "type": "local",
28
- "command": ["npx", "--yes", "--package", "thumbgate@1.0.0", "thumbgate", "serve"],
28
+ "command": ["npx", "--yes", "--package", "thumbgate@1.1.0", "thumbgate", "serve"],
29
29
  "enabled": true
30
30
  }
31
31
  }
package/public/index.html CHANGED
@@ -66,7 +66,9 @@ __GA_BOOTSTRAP__
66
66
  "Background Agent Governance — per-agent pass rates, CI auto-feedback",
67
67
  "Memory Migration — imports Claude Code MEMORY.md into unlimited SQLite DB",
68
68
  "Prompt-Level DLP — scans tool call inputs before execution",
69
- "Per-Step Scoring — every gate decision becomes a DPO/KTO training signal"
69
+ "Per-Step Scoring — every gate decision becomes a DPO/KTO training signal",
70
+ "HuggingFace Export — share PII-redacted agent traces as open training datasets",
71
+ "Unified Context — one-call context assembly with session, lessons, guards, and code-graph"
70
72
  ],
71
73
  "offers": [
72
74
  {
@@ -578,7 +580,7 @@ __GA_BOOTSTRAP__
578
580
  <!-- HOW IT WORKS -->
579
581
  <section class="how-it-works" id="how-it-works">
580
582
  <div class="container">
581
- <div class="section-label">New in v1.0.0</div>
583
+ <div class="section-label">New in v1.1.0</div>
582
584
  <h2 class="section-title">Three steps to stop repeated AI failures</h2>
583
585
  <div class="steps">
584
586
  <div class="step">
@@ -670,6 +672,7 @@ __GA_BOOTSTRAP__
670
672
  <li>All MCP integrations (Claude Code, Cursor, Codex, etc.)</li>
671
673
  <li>PreToolUse hook blocking</li>
672
674
  <li>Local SQLite lesson DB</li>
675
+ <li>Unified context assembly — one call gets session, lessons, guards, and code-graph</li>
673
676
  <li><a href="/guide" style="color:var(--cyan);text-decoration:underline;">Setup guide for all agents →</a></li>
674
677
  </ul>
675
678
  <a href="https://www.npmjs.com/package/thumbgate" target="_blank" rel="noopener" class="btn-free">Install Free</a>
@@ -698,6 +701,7 @@ __GA_BOOTSTRAP__
698
701
  <li><a href="/dashboard" style="color:var(--cyan);text-decoration:underline;">Visual gate debugger →</a> see every blocked action and the gate that fired so you can trust the system in minutes</li>
699
702
  <li>Auto-connect — activate once with your license key, then your running agents appear automatically on your local dashboard</li>
700
703
  <li><a href="/dashboard" style="color:var(--cyan);text-decoration:underline;">DPO training data export →</a> turn real thumbs-downs into ready-to-use preference pairs for fine-tuning (LoRA / JSONL)</li>
704
+ <li><strong>HuggingFace dataset export</strong> — share PII-redacted agent traces as open training datasets (<code>npm run export:hf</code>)</li>
701
705
  <li><strong>Model Hardening Advisor</strong> — get recommendations on when and how to fine-tune your model to natively avoid recurring failures</li>
702
706
  <li>Personal local dashboard — every Pro user gets a localhost dashboard without extra cloud setup</li>
703
707
  <li>Founder-license support — we help you wire the riskiest flows first: migrations, force-pushes, deploys, and CI</li>
@@ -835,7 +839,7 @@ __GA_BOOTSTRAP__
835
839
  <a href="https://www.linkedin.com/in/igorganapolsky" target="_blank" rel="noopener">LinkedIn</a>
836
840
  <a href="/blog">Blog</a>
837
841
  </div>
838
- <span class="footer-copy">© 2026 Max Smith KDP LLC · MIT License · v1.0.0</span>
842
+ <span class="footer-copy">© 2026 Max Smith KDP LLC · MIT License · v1.1.0</span>
839
843
  </div>
840
844
  </footer>
841
845
 
@@ -0,0 +1,293 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * HuggingFace Dataset Exporter
6
+ *
7
+ * Exports ThumbGate agent traces as a HuggingFace-compatible dataset in two formats:
8
+ *
9
+ * 1. Agent Traces (traces split) — raw feedback entries with tool calls, signals,
10
+ * context, and outcomes. Matches the "share your agent traces" initiative.
11
+ *
12
+ * 2. DPO Preferences (preferences split) — chosen/rejected preference pairs
13
+ * derived from error→learning memory promotion. Ready for DPO/RLHF training.
14
+ *
15
+ * Output: Parquet-compatible JSONL files + dataset_info.json (HF Dataset Card metadata).
16
+ *
17
+ * HuggingFace Datasets format:
18
+ * dataset_dir/
19
+ * dataset_info.json — metadata, features schema, splits
20
+ * traces.jsonl — agent trace rows
21
+ * preferences.jsonl — DPO preference pair rows
22
+ */
23
+
24
+ const fs = require('fs');
25
+ const path = require('path');
26
+ const { resolveFeedbackDir } = require('./feedback-paths');
27
+ const { exportDpoFromMemories } = require('./export-dpo-pairs');
28
+ const { getProvenance } = require('./contextfs');
29
+
30
+ // ---------------------------------------------------------------------------
31
+ // Helpers
32
+ // ---------------------------------------------------------------------------
33
+
34
+ function readJSONL(filePath) {
35
+ if (!fs.existsSync(filePath)) return [];
36
+ const raw = fs.readFileSync(filePath, 'utf-8').trim();
37
+ if (!raw) return [];
38
+ return raw
39
+ .split('\n')
40
+ .map((line) => {
41
+ try { return JSON.parse(line); } catch { return null; }
42
+ })
43
+ .filter(Boolean);
44
+ }
45
+
46
+ function ensureDir(dirPath) {
47
+ if (!fs.existsSync(dirPath)) {
48
+ fs.mkdirSync(dirPath, { recursive: true });
49
+ }
50
+ }
51
+
52
+ function writeJSONL(filePath, rows) {
53
+ const content = rows.map((row) => JSON.stringify(row)).join('\n');
54
+ fs.writeFileSync(filePath, content ? `${content}\n` : '');
55
+ }
56
+
57
+ // ---------------------------------------------------------------------------
58
+ // PII / path redaction
59
+ // ---------------------------------------------------------------------------
60
+
61
+ function redactPaths(text) {
62
+ if (!text || typeof text !== 'string') return text || '';
63
+ return text
64
+ .replace(/\/Users\/[^\s/]+/g, '/Users/redacted')
65
+ .replace(/\/home\/[^\s/]+/g, '/home/redacted')
66
+ .replace(/C:\\Users\\[^\s\\]+/g, 'C:\\Users\\redacted');
67
+ }
68
+
69
+ function redactEntry(obj) {
70
+ if (!obj || typeof obj !== 'object') return obj;
71
+ const out = {};
72
+ for (const [key, value] of Object.entries(obj)) {
73
+ if (typeof value === 'string') {
74
+ out[key] = redactPaths(value);
75
+ } else if (Array.isArray(value)) {
76
+ out[key] = value.map((v) => (typeof v === 'string' ? redactPaths(v) : v));
77
+ } else {
78
+ out[key] = value;
79
+ }
80
+ }
81
+ return out;
82
+ }
83
+
84
+ // ---------------------------------------------------------------------------
85
+ // Trace row builder — converts feedback-log entries to HF trace rows
86
+ // ---------------------------------------------------------------------------
87
+
88
+ function buildTraceRow(entry, index) {
89
+ return {
90
+ trace_id: entry.id || `trace_${index}`,
91
+ timestamp: entry.timestamp || null,
92
+ signal: entry.signal || entry.feedback || 'unknown',
93
+ tool_name: entry.toolName || entry.actionType || 'unknown',
94
+ context: redactPaths(entry.context || ''),
95
+ what_worked: redactPaths(entry.whatWorked || ''),
96
+ what_went_wrong: redactPaths(entry.whatWentWrong || ''),
97
+ what_to_change: redactPaths(entry.whatToChange || ''),
98
+ tags: Array.isArray(entry.tags) ? entry.tags : [],
99
+ failure_type: entry.failureType || null,
100
+ source: 'thumbgate',
101
+ };
102
+ }
103
+
104
+ // ---------------------------------------------------------------------------
105
+ // Preference row builder — converts DPO pairs to HF preference rows
106
+ // ---------------------------------------------------------------------------
107
+
108
+ function buildPreferenceRow(pair, index) {
109
+ return {
110
+ pair_id: `pref_${index}`,
111
+ prompt: redactPaths(pair.prompt || ''),
112
+ chosen: redactPaths(pair.chosen || ''),
113
+ rejected: redactPaths(pair.rejected || ''),
114
+ match_score: pair.metadata ? pair.metadata.matchScore : null,
115
+ matched_keys: pair.metadata ? pair.metadata.matchedKeys || [] : [],
116
+ rubric_delta: pair.metadata && pair.metadata.rubric
117
+ ? pair.metadata.rubric.weightedDelta
118
+ : null,
119
+ source: 'thumbgate',
120
+ };
121
+ }
122
+
123
+ // ---------------------------------------------------------------------------
124
+ // Dataset info (HuggingFace Dataset Card metadata)
125
+ // ---------------------------------------------------------------------------
126
+
127
+ function buildDatasetInfo({ traceCount, preferenceCount, exportedAt }) {
128
+ return {
129
+ dataset_info: {
130
+ description: 'Agent traces and DPO preference pairs from ThumbGate — pre-action gates for AI coding agents. Contains real-world tool call feedback, failure patterns, and learned corrections.',
131
+ citation: '',
132
+ homepage: 'https://github.com/IgorGanapolsky/ThumbGate',
133
+ license: 'MIT',
134
+ features: {
135
+ traces: {
136
+ trace_id: { dtype: 'string' },
137
+ timestamp: { dtype: 'string' },
138
+ signal: { dtype: 'string' },
139
+ tool_name: { dtype: 'string' },
140
+ context: { dtype: 'string' },
141
+ what_worked: { dtype: 'string' },
142
+ what_went_wrong: { dtype: 'string' },
143
+ what_to_change: { dtype: 'string' },
144
+ tags: { dtype: 'list', inner: { dtype: 'string' } },
145
+ failure_type: { dtype: 'string' },
146
+ source: { dtype: 'string' },
147
+ },
148
+ preferences: {
149
+ pair_id: { dtype: 'string' },
150
+ prompt: { dtype: 'string' },
151
+ chosen: { dtype: 'string' },
152
+ rejected: { dtype: 'string' },
153
+ match_score: { dtype: 'float32' },
154
+ matched_keys: { dtype: 'list', inner: { dtype: 'string' } },
155
+ rubric_delta: { dtype: 'float32' },
156
+ source: { dtype: 'string' },
157
+ },
158
+ },
159
+ splits: {
160
+ traces: { num_examples: traceCount },
161
+ preferences: { num_examples: preferenceCount },
162
+ },
163
+ },
164
+ exported_at: exportedAt,
165
+ exporter: 'thumbgate/export-hf-dataset',
166
+ version: '1.0.0',
167
+ };
168
+ }
169
+
170
+ // ---------------------------------------------------------------------------
171
+ // Main export function
172
+ // ---------------------------------------------------------------------------
173
+
174
+ /**
175
+ * Export ThumbGate data as a HuggingFace-compatible dataset.
176
+ *
177
+ * @param {Object} options
178
+ * @param {string} [options.outputDir] - Directory to write dataset files
179
+ * @param {string} [options.feedbackDir] - Override feedback data directory
180
+ * @param {boolean} [options.includeProvenance] - Include provenance events in traces
181
+ * @returns {Object} Export summary
182
+ */
183
+ function exportHfDataset(options = {}) {
184
+ const feedbackDir = options.feedbackDir || resolveFeedbackDir();
185
+ const outputDir = options.outputDir || path.join(feedbackDir, 'hf-dataset');
186
+ const includeProvenance = options.includeProvenance !== false;
187
+
188
+ ensureDir(outputDir);
189
+
190
+ // --- Traces split ---
191
+ const feedbackLogPath = path.join(feedbackDir, 'feedback-log.jsonl');
192
+ const feedbackEntries = readJSONL(feedbackLogPath);
193
+ const traceRows = feedbackEntries.map((entry, i) => buildTraceRow(redactEntry(entry), i));
194
+
195
+ // Optionally append provenance events as traces
196
+ if (includeProvenance) {
197
+ try {
198
+ const provenanceEvents = getProvenance(200);
199
+ for (const evt of provenanceEvents) {
200
+ traceRows.push({
201
+ trace_id: evt.id || `prov_${traceRows.length}`,
202
+ timestamp: evt.timestamp || null,
203
+ signal: 'provenance',
204
+ tool_name: evt.type || 'context_assembly',
205
+ context: redactPaths(JSON.stringify(evt).slice(0, 500)),
206
+ what_worked: '',
207
+ what_went_wrong: '',
208
+ what_to_change: '',
209
+ tags: ['provenance'],
210
+ failure_type: null,
211
+ source: 'thumbgate',
212
+ });
213
+ }
214
+ } catch {
215
+ // Provenance read failure should not break export
216
+ }
217
+ }
218
+
219
+ writeJSONL(path.join(outputDir, 'traces.jsonl'), traceRows);
220
+
221
+ // --- Preferences split ---
222
+ const memoryLogPath = path.join(feedbackDir, 'memory-log.jsonl');
223
+ const memories = readJSONL(memoryLogPath);
224
+ let preferenceRows = [];
225
+
226
+ if (memories.length > 0) {
227
+ try {
228
+ const dpoResult = exportDpoFromMemories(memories);
229
+ preferenceRows = dpoResult.pairs.map((pair, i) => buildPreferenceRow(pair, i));
230
+ } catch {
231
+ // DPO export failure should not break the traces export
232
+ }
233
+ }
234
+
235
+ writeJSONL(path.join(outputDir, 'preferences.jsonl'), preferenceRows);
236
+
237
+ // --- Dataset info ---
238
+ const exportedAt = new Date().toISOString();
239
+ const info = buildDatasetInfo({
240
+ traceCount: traceRows.length,
241
+ preferenceCount: preferenceRows.length,
242
+ exportedAt,
243
+ });
244
+ fs.writeFileSync(
245
+ path.join(outputDir, 'dataset_info.json'),
246
+ JSON.stringify(info, null, 2) + '\n',
247
+ );
248
+
249
+ return {
250
+ outputDir,
251
+ traceCount: traceRows.length,
252
+ preferenceCount: preferenceRows.length,
253
+ files: ['traces.jsonl', 'preferences.jsonl', 'dataset_info.json'],
254
+ exportedAt,
255
+ };
256
+ }
257
+
258
+ // ---------------------------------------------------------------------------
259
+ // CLI
260
+ // ---------------------------------------------------------------------------
261
+
262
+ function main() {
263
+ const args = {};
264
+ process.argv.slice(2).forEach((arg) => {
265
+ if (!arg.startsWith('--')) return;
266
+ const [key, ...rest] = arg.slice(2).split('=');
267
+ args[key] = rest.length ? rest.join('=') : true;
268
+ });
269
+
270
+ const result = exportHfDataset({
271
+ outputDir: args.output || undefined,
272
+ includeProvenance: args.provenance !== 'false',
273
+ });
274
+
275
+ console.log(`Exported HuggingFace dataset to ${result.outputDir}`);
276
+ console.log(` Traces: ${result.traceCount}`);
277
+ console.log(` Preferences: ${result.preferenceCount}`);
278
+ console.log(` Files: ${result.files.join(', ')}`);
279
+ }
280
+
281
+ if (require.main === module) {
282
+ main();
283
+ }
284
+
285
+ module.exports = {
286
+ exportHfDataset,
287
+ buildTraceRow,
288
+ buildPreferenceRow,
289
+ buildDatasetInfo,
290
+ redactPaths,
291
+ redactEntry,
292
+ readJSONL,
293
+ };
@@ -399,6 +399,17 @@ const TOOLS = [
399
399
  },
400
400
  },
401
401
  }),
402
+ destructiveTool({
403
+ name: 'export_hf_dataset',
404
+ description: 'Export ThumbGate agent traces and DPO preference pairs as a HuggingFace-compatible dataset. Produces traces.jsonl, preferences.jsonl, and dataset_info.json with PII-redacted paths. Ready for huggingface-cli upload.',
405
+ inputSchema: {
406
+ type: 'object',
407
+ properties: {
408
+ outputDir: { type: 'string', description: 'Output directory (default: feedback-dir/hf-dataset)' },
409
+ includeProvenance: { type: 'boolean', description: 'Include provenance events in traces (default: true)' },
410
+ },
411
+ },
412
+ }),
402
413
  destructiveTool({
403
414
  name: 'export_databricks_bundle',
404
415
  description: 'Export ThumbGate logs and proof artifacts as a Databricks-ready analytics bundle',