thumbgate 1.4.3 → 1.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/.well-known/mcp/server-card.json +1 -1
- package/adapters/README.md +1 -1
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/codex/config.toml +2 -2
- package/adapters/mcp/server-stdio.js +1 -1
- package/adapters/opencode/opencode.json +1 -1
- package/package.json +157 -9
- package/scripts/statusline.sh +1 -0
- package/src/api/server.js +113 -16
- package/src/index.js +3 -0
- package/.claude-plugin/bundle/icon.png +0 -0
- package/.claude-plugin/bundle/icon.svg +0 -18
- package/.claude-plugin/bundle/server/index.js +0 -24
- package/adapters/chatgpt/INSTALL.md +0 -158
- package/adapters/perplexity/.mcp.json +0 -36
- package/adapters/perplexity/config.toml +0 -16
- package/adapters/perplexity/opencode.json +0 -29
- package/bin/memory.sh +0 -64
- package/bin/obsidian-sync.sh +0 -20
- package/plugins/amp-skill/INSTALL.md +0 -52
- package/plugins/amp-skill/SKILL.md +0 -64
- package/plugins/claude-codex-bridge/.claude-plugin/plugin.json +0 -22
- package/plugins/claude-codex-bridge/.mcp.json +0 -14
- package/plugins/claude-codex-bridge/INSTALL.md +0 -43
- package/plugins/claude-codex-bridge/README.md +0 -46
- package/plugins/claude-codex-bridge/scripts/codex-bridge.js +0 -286
- package/plugins/claude-codex-bridge/skills/adversarial-review/SKILL.md +0 -24
- package/plugins/claude-codex-bridge/skills/result/SKILL.md +0 -22
- package/plugins/claude-codex-bridge/skills/review/SKILL.md +0 -28
- package/plugins/claude-codex-bridge/skills/second-pass/SKILL.md +0 -27
- package/plugins/claude-codex-bridge/skills/setup/SKILL.md +0 -21
- package/plugins/claude-codex-bridge/skills/status/SKILL.md +0 -19
- package/plugins/claude-skill/INSTALL.md +0 -55
- package/plugins/claude-skill/SKILL.md +0 -46
- package/plugins/codex-profile/.codex-plugin/plugin.json +0 -43
- package/plugins/codex-profile/.mcp.json +0 -14
- package/plugins/codex-profile/AGENTS.md +0 -20
- package/plugins/codex-profile/INSTALL.md +0 -89
- package/plugins/codex-profile/README.md +0 -61
- package/plugins/cursor-marketplace/.cursor-plugin/plugin.json +0 -23
- package/plugins/cursor-marketplace/CHANGELOG.md +0 -30
- package/plugins/cursor-marketplace/LICENSE +0 -21
- package/plugins/cursor-marketplace/README.md +0 -124
- package/plugins/cursor-marketplace/agents/reliability-reviewer.md +0 -31
- package/plugins/cursor-marketplace/assets/logo-400x400.png +0 -0
- package/plugins/cursor-marketplace/commands/capture-feedback.md +0 -33
- package/plugins/cursor-marketplace/commands/check-gates.md +0 -25
- package/plugins/cursor-marketplace/commands/show-lessons.md +0 -27
- package/plugins/cursor-marketplace/hooks/hooks.json +0 -10
- package/plugins/cursor-marketplace/mcp.json +0 -14
- package/plugins/cursor-marketplace/rules/feedback-capture.mdc +0 -34
- package/plugins/cursor-marketplace/rules/pre-action-gates.mdc +0 -30
- package/plugins/cursor-marketplace/rules/session-continuity.mdc +0 -28
- package/plugins/cursor-marketplace/scripts/gate-check.sh +0 -21
- package/plugins/cursor-marketplace/skills/capture-feedback/SKILL.md +0 -48
- package/plugins/cursor-marketplace/skills/prevention-rules/SKILL.md +0 -31
- package/plugins/cursor-marketplace/skills/recall-context/SKILL.md +0 -30
- package/plugins/cursor-marketplace/skills/search-lessons/SKILL.md +0 -33
- package/plugins/gemini-extension/INSTALL.md +0 -92
- package/plugins/gemini-extension/gemini_prompt.txt +0 -14
- package/plugins/gemini-extension/tool_contract.json +0 -45
- package/plugins/opencode-profile/INSTALL.md +0 -57
- package/public/assets/instagram-card.png +0 -0
- package/public/assets/tiktok-agent-memory.mp4 +0 -0
- package/public/blog.html +0 -474
- package/public/compare/mem0.html +0 -189
- package/public/compare/speclock.html +0 -180
- package/public/compare.html +0 -310
- package/public/dashboard.html +0 -1100
- package/public/guide.html +0 -317
- package/public/guides/claude-code-prevent-repeated-mistakes.html +0 -161
- package/public/guides/codex-cli-guardrails.html +0 -158
- package/public/guides/cursor-prevent-repeated-mistakes.html +0 -161
- package/public/guides/pre-action-gates.html +0 -162
- package/public/guides/stop-repeated-ai-agent-mistakes.html +0 -159
- package/public/index.html +0 -1225
- package/public/js/buyer-intent.js +0 -252
- package/public/learn/agent-harness-pattern.html +0 -180
- package/public/learn/ai-agent-persistent-memory.html +0 -203
- package/public/learn/learn.css +0 -45
- package/public/learn/mcp-pre-action-gates-explained.html +0 -172
- package/public/learn/stop-ai-agent-force-push.html +0 -134
- package/public/learn/vibe-coding-safety-net.html +0 -142
- package/public/learn.html +0 -274
- package/public/lessons.html +0 -967
- package/public/llm-context.md +0 -156
- package/public/pro.html +0 -1087
- package/public/vercel.json +0 -8
- package/scripts/a2ui-engine.js +0 -73
- package/scripts/adk-consolidator.js +0 -274
- package/scripts/agent-security-hardening.js +0 -225
- package/scripts/ai-search-visibility.js +0 -116
- package/scripts/autonomous-sales-agent.js +0 -39
- package/scripts/autoresearch-runner.js +0 -216
- package/scripts/background-agent-governance.js +0 -229
- package/scripts/behavioral-extraction.js +0 -93
- package/scripts/budget-enforcer.js +0 -173
- package/scripts/budget-guard.js +0 -173
- package/scripts/build-claude-mcpb.js +0 -255
- package/scripts/build-codex-plugin.js +0 -152
- package/scripts/capture-railway-diagnostics.sh +0 -97
- package/scripts/changeset-check.js +0 -372
- package/scripts/check-congruence.js +0 -443
- package/scripts/computer-use-firewall.js +0 -280
- package/scripts/content-engine/linkedin-content-generator.js +0 -154
- package/scripts/content-engine/output/linkedin-memento-validation.md +0 -17
- package/scripts/content-engine/output/linkedin-posts-2026-04-09.md +0 -175
- package/scripts/content-engine/reddit-thread-finder.js +0 -154
- package/scripts/context-engine.js +0 -710
- package/scripts/daily-digest.js +0 -11
- package/scripts/data-governance.js +0 -173
- package/scripts/deploy-gcp.sh +0 -44
- package/scripts/deploy-policy.js +0 -249
- package/scripts/disagreement-mining.js +0 -315
- package/scripts/dpo-optimizer.js +0 -206
- package/scripts/ensure-repo-bootstrap.js +0 -130
- package/scripts/ephemeral-agent-store.js +0 -212
- package/scripts/eval-harness.js +0 -56
- package/scripts/export-kto-pairs.js +0 -309
- package/scripts/export-training.js +0 -446
- package/scripts/feedback-fallback.js +0 -111
- package/scripts/feedback-inbox-read.js +0 -162
- package/scripts/feedback-root-consolidator.js +0 -233
- package/scripts/feedback-to-memory.js +0 -185
- package/scripts/gate-satisfy.js +0 -42
- package/scripts/generate-paperbanana-diagrams.sh +0 -99
- package/scripts/generate-pretool-hook.sh +0 -40
- package/scripts/github-about.js +0 -430
- package/scripts/github-outreach.js +0 -65
- package/scripts/gtm-revenue-loop.js +0 -535
- package/scripts/hallucination-detector.js +0 -226
- package/scripts/hf-papers.js +0 -317
- package/scripts/hook-auto-capture.sh +0 -100
- package/scripts/hook-stop-pr-thread-check.sh +0 -68
- package/scripts/hook-stop-self-score.sh +0 -51
- package/scripts/hook-stop-verify-deploy.sh +0 -31
- package/scripts/hook-verify-before-done.sh +0 -20
- package/scripts/managed-dpo-export.js +0 -91
- package/scripts/markdown-escape.js +0 -12
- package/scripts/marketing-experiment.js +0 -657
- package/scripts/memalign-recall.js +0 -111
- package/scripts/memory-migration.js +0 -296
- package/scripts/meta-policy.js +0 -190
- package/scripts/metered-billing.js +0 -16
- package/scripts/model-tier-router.js +0 -310
- package/scripts/money-watcher.js +0 -218
- package/scripts/multi-hop-recall.js +0 -240
- package/scripts/per-step-scoring.js +0 -163
- package/scripts/perplexity-command-center.js +0 -644
- package/scripts/perplexity-marketing.js +0 -454
- package/scripts/pii-scanner.js +0 -153
- package/scripts/plan-gate.js +0 -154
- package/scripts/post-everywhere.js +0 -341
- package/scripts/post-to-x-retry.sh +0 -22
- package/scripts/post-to-x.js +0 -369
- package/scripts/pr-manager.js +0 -421
- package/scripts/principle-extractor.js +0 -162
- package/scripts/pro-features.js +0 -41
- package/scripts/prompt-dlp.js +0 -222
- package/scripts/prove-adapters.js +0 -860
- package/scripts/prove-attribution.js +0 -361
- package/scripts/prove-automation.js +0 -651
- package/scripts/prove-autoresearch.js +0 -304
- package/scripts/prove-claim-verification.js +0 -277
- package/scripts/prove-cloudflare-sandbox.js +0 -161
- package/scripts/prove-data-pipeline.js +0 -408
- package/scripts/prove-data-quality.js +0 -227
- package/scripts/prove-evolution.js +0 -352
- package/scripts/prove-harnesses.js +0 -287
- package/scripts/prove-intelligence.js +0 -257
- package/scripts/prove-lancedb.js +0 -425
- package/scripts/prove-local-intelligence.js +0 -340
- package/scripts/prove-loop-closure.js +0 -263
- package/scripts/prove-packaged-runtime.js +0 -327
- package/scripts/prove-predictive-insights.js +0 -355
- package/scripts/prove-runtime.js +0 -363
- package/scripts/prove-seo-gsd.js +0 -234
- package/scripts/prove-settings.js +0 -279
- package/scripts/prove-subway-upgrades.js +0 -277
- package/scripts/prove-tessl.js +0 -229
- package/scripts/prove-training-export.js +0 -325
- package/scripts/prove-workflow-contract.js +0 -112
- package/scripts/prove-xmemory.js +0 -332
- package/scripts/publish-decision.js +0 -159
- package/scripts/ralph-loop.js +0 -376
- package/scripts/ralph-mode-ci.js +0 -434
- package/scripts/reddit-dm-outreach.js +0 -192
- package/scripts/reddit-monitor-cron.sh +0 -26
- package/scripts/reminder-engine.js +0 -132
- package/scripts/revenue-status.js +0 -472
- package/scripts/rotate-stripe-webhook-secret.js +0 -314
- package/scripts/schedule-manager.js +0 -249
- package/scripts/self-healing-check.js +0 -193
- package/scripts/session-analyzer.js +0 -533
- package/scripts/shieldcortex-memory-firewall-runner.mjs +0 -53
- package/scripts/skill-exporter.js +0 -260
- package/scripts/skill-materializer.js +0 -134
- package/scripts/skill-packs.js +0 -136
- package/scripts/skill-proposer.js +0 -99
- package/scripts/skill-quality-tracker.js +0 -282
- package/scripts/slow-loop.js +0 -72
- package/scripts/social-analytics/db/marketing-db.js +0 -179
- package/scripts/social-analytics/db/schema.sql +0 -55
- package/scripts/social-analytics/digest.js +0 -256
- package/scripts/social-analytics/engagement-audit.js +0 -185
- package/scripts/social-analytics/generate-instagram-card.js +0 -123
- package/scripts/social-analytics/generate-slides.js +0 -268
- package/scripts/social-analytics/instagram-thumbgate-post.js +0 -111
- package/scripts/social-analytics/install-growth-automation.js +0 -114
- package/scripts/social-analytics/load-env.js +0 -77
- package/scripts/social-analytics/mcp-server.js +0 -289
- package/scripts/social-analytics/normalizer.js +0 -580
- package/scripts/social-analytics/notify.js +0 -162
- package/scripts/social-analytics/poll-all.js +0 -107
- package/scripts/social-analytics/pollers/github.js +0 -195
- package/scripts/social-analytics/pollers/instagram.js +0 -253
- package/scripts/social-analytics/pollers/linkedin.js +0 -340
- package/scripts/social-analytics/pollers/plausible.js +0 -245
- package/scripts/social-analytics/pollers/reddit.js +0 -306
- package/scripts/social-analytics/pollers/threads.js +0 -233
- package/scripts/social-analytics/pollers/tiktok.js +0 -203
- package/scripts/social-analytics/pollers/x.js +0 -227
- package/scripts/social-analytics/pollers/youtube.js +0 -304
- package/scripts/social-analytics/pollers/zernio.js +0 -183
- package/scripts/social-analytics/post-video.js +0 -316
- package/scripts/social-analytics/publish-instagram-thumbgate.js +0 -104
- package/scripts/social-analytics/publish-thumbgate-launch.js +0 -322
- package/scripts/social-analytics/publishers/devto.js +0 -122
- package/scripts/social-analytics/publishers/instagram.js +0 -317
- package/scripts/social-analytics/publishers/linkedin.js +0 -294
- package/scripts/social-analytics/publishers/reddit.js +0 -385
- package/scripts/social-analytics/publishers/threads.js +0 -275
- package/scripts/social-analytics/publishers/tiktok.js +0 -217
- package/scripts/social-analytics/publishers/x.js +0 -259
- package/scripts/social-analytics/publishers/youtube.js +0 -223
- package/scripts/social-analytics/publishers/zernio.js +0 -568
- package/scripts/social-analytics/reconcile-thumbgate-campaign.js +0 -165
- package/scripts/social-analytics/run-digest.js +0 -34
- package/scripts/social-analytics/schedule-thumbgate-campaign.js +0 -275
- package/scripts/social-analytics/store.js +0 -455
- package/scripts/social-analytics/sync-launch-assets.js +0 -185
- package/scripts/social-analytics/utm.js +0 -143
- package/scripts/social-pipeline.js +0 -2626
- package/scripts/social-post-hourly.js +0 -228
- package/scripts/social-quality-gate.js +0 -134
- package/scripts/social-reply-monitor.js +0 -592
- package/scripts/status-dashboard.js +0 -155
- package/scripts/stripe-live-status.js +0 -115
- package/scripts/subagent-profiles.js +0 -79
- package/scripts/sync-branch-protection.js +0 -340
- package/scripts/sync-gh-secrets-from-env.sh +0 -70
- package/scripts/sync-github-about.js +0 -55
- package/scripts/sync-version.js +0 -479
- package/scripts/synthetic-dpo.js +0 -234
- package/scripts/tessl-export.js +0 -369
- package/scripts/test-coverage.js +0 -128
- package/scripts/thumbgate-bench.js +0 -494
- package/scripts/thumbgate_session_start.sh +0 -32
- package/scripts/train_from_feedback.py +0 -929
- package/scripts/validate-feedback.js +0 -581
- package/scripts/verify-obsidian-setup.sh +0 -269
- package/scripts/verify-run.js +0 -269
- package/scripts/weekly-auto-post.js +0 -124
- package/scripts/x-autonomous-marketing.js +0 -139
package/scripts/synthetic-dpo.js
DELETED
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Synthetic DPO Pair Augmentation — expands real feedback into larger training datasets.
|
|
6
|
-
*
|
|
7
|
-
* Takes existing DPO pairs (from export-dpo-pairs.js) and generates synthetic
|
|
8
|
-
* variations to increase dataset size for fine-tuning:
|
|
9
|
-
*
|
|
10
|
-
* 1. Principle extraction: generalize specific errors into abstract rules
|
|
11
|
-
* 2. Contrastive pairing: match unpaired errors/learnings by domain similarity
|
|
12
|
-
* 3. Scenario variation: rephrase prompts for the same chosen/rejected pair
|
|
13
|
-
*
|
|
14
|
-
* Inspired by Chroma Context-1's scalable synthetic task generation.
|
|
15
|
-
* Pro-only feature — gated via requirePro('dpo-synthesis').
|
|
16
|
-
*
|
|
17
|
-
* @module synthetic-dpo
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
const { requirePro } = require('./pro-features');
|
|
21
|
-
const { extractDomainKeys, domainOverlap, inferPrompt, buildRubricDelta } = require('./export-dpo-pairs');
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Extract an abstract principle from an error+learning pair.
|
|
25
|
-
* Turns "never run DROP on production tables" into a generalized rule.
|
|
26
|
-
*/
|
|
27
|
-
function extractPrinciple(pair) {
|
|
28
|
-
const rejected = pair.rejected || '';
|
|
29
|
-
const chosen = pair.chosen || '';
|
|
30
|
-
const matchedKeys = pair.metadata?.matchedKeys || [];
|
|
31
|
-
|
|
32
|
-
// Build principle from the domain keys and the contrast
|
|
33
|
-
const domain = matchedKeys.length > 0
|
|
34
|
-
? matchedKeys.join(', ')
|
|
35
|
-
: 'general';
|
|
36
|
-
|
|
37
|
-
// Extract the "don't do X, do Y instead" pattern
|
|
38
|
-
const dontDo = rejected.length > 120
|
|
39
|
-
? rejected.slice(0, 120).trim() + '...'
|
|
40
|
-
: rejected;
|
|
41
|
-
const doInstead = chosen.length > 120
|
|
42
|
-
? chosen.slice(0, 120).trim() + '...'
|
|
43
|
-
: chosen;
|
|
44
|
-
|
|
45
|
-
return {
|
|
46
|
-
domain,
|
|
47
|
-
anti_pattern: dontDo,
|
|
48
|
-
correct_pattern: doInstead,
|
|
49
|
-
principle: `In ${domain} tasks: avoid "${truncate(dontDo, 60)}" — instead "${truncate(doInstead, 60)}"`,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function truncate(str, maxLen) {
|
|
54
|
-
if (str.length <= maxLen) return str;
|
|
55
|
-
return str.slice(0, maxLen - 3) + '...';
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Generate scenario variations for a DPO pair by rephrasing the prompt.
|
|
60
|
-
* Creates 1-2 synthetic pairs with different prompt framings.
|
|
61
|
-
*/
|
|
62
|
-
function generateScenarioVariations(pair) {
|
|
63
|
-
const variations = [];
|
|
64
|
-
const matchedKeys = pair.metadata?.matchedKeys || [];
|
|
65
|
-
const domain = matchedKeys.join(', ') || 'this domain';
|
|
66
|
-
|
|
67
|
-
// Variation 1: "What should be avoided?" framing
|
|
68
|
-
variations.push({
|
|
69
|
-
prompt: `In ${domain}: what is the wrong approach and what should be done instead?`,
|
|
70
|
-
chosen: pair.chosen,
|
|
71
|
-
rejected: pair.rejected,
|
|
72
|
-
metadata: {
|
|
73
|
-
...pair.metadata,
|
|
74
|
-
synthetic: true,
|
|
75
|
-
syntheticType: 'scenario_variation',
|
|
76
|
-
syntheticVariant: 'avoidance_framing',
|
|
77
|
-
sourceId: pair.metadata?.errorId,
|
|
78
|
-
},
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
// Variation 2: "Best practice" framing (only if we have enough context)
|
|
82
|
-
if (matchedKeys.length > 0) {
|
|
83
|
-
variations.push({
|
|
84
|
-
prompt: `What is the best practice for ${domain}? Compare the correct approach with a common mistake.`,
|
|
85
|
-
chosen: pair.chosen,
|
|
86
|
-
rejected: pair.rejected,
|
|
87
|
-
metadata: {
|
|
88
|
-
...pair.metadata,
|
|
89
|
-
synthetic: true,
|
|
90
|
-
syntheticType: 'scenario_variation',
|
|
91
|
-
syntheticVariant: 'best_practice_framing',
|
|
92
|
-
sourceId: pair.metadata?.errorId,
|
|
93
|
-
},
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return variations;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Build contrastive pairs from unpaired errors and learnings.
|
|
102
|
-
* Uses softer domain matching (single key overlap) to find weak matches
|
|
103
|
-
* that wouldn't qualify for primary pairing but are useful for training.
|
|
104
|
-
*/
|
|
105
|
-
function buildContrastivePairs(unpairedErrors, unpairedLearnings) {
|
|
106
|
-
const pairs = [];
|
|
107
|
-
const usedErrors = new Set();
|
|
108
|
-
const usedLearnings = new Set();
|
|
109
|
-
|
|
110
|
-
const errorKeys = unpairedErrors.map((e) => ({ memory: e, keys: extractDomainKeys(e) }));
|
|
111
|
-
const learningKeys = unpairedLearnings.map((l) => ({ memory: l, keys: extractDomainKeys(l) }));
|
|
112
|
-
|
|
113
|
-
// Relaxed matching: 1+ key overlap (primary pairing requires higher scores)
|
|
114
|
-
for (const err of errorKeys) {
|
|
115
|
-
if (usedErrors.has(err.memory.id)) continue;
|
|
116
|
-
|
|
117
|
-
let best = null;
|
|
118
|
-
let bestOverlap = 0;
|
|
119
|
-
|
|
120
|
-
for (const learn of learningKeys) {
|
|
121
|
-
if (usedLearnings.has(learn.memory.id)) continue;
|
|
122
|
-
const overlap = domainOverlap(err.keys, learn.keys);
|
|
123
|
-
if (overlap > bestOverlap) {
|
|
124
|
-
best = learn;
|
|
125
|
-
bestOverlap = overlap;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
if (best && bestOverlap >= 1) {
|
|
130
|
-
const rubric = buildRubricDelta(err.memory, best.memory);
|
|
131
|
-
pairs.push({
|
|
132
|
-
prompt: inferPrompt(err.memory, best.memory),
|
|
133
|
-
chosen: best.memory.content,
|
|
134
|
-
rejected: err.memory.content,
|
|
135
|
-
metadata: {
|
|
136
|
-
errorId: err.memory.id,
|
|
137
|
-
learningId: best.memory.id,
|
|
138
|
-
matchScore: bestOverlap,
|
|
139
|
-
overlapScore: bestOverlap,
|
|
140
|
-
matchedKeys: err.keys.filter((k) => best.keys.includes(k)),
|
|
141
|
-
errorTitle: err.memory.title,
|
|
142
|
-
learningTitle: best.memory.title,
|
|
143
|
-
rubric,
|
|
144
|
-
synthetic: true,
|
|
145
|
-
syntheticType: 'contrastive_pair',
|
|
146
|
-
},
|
|
147
|
-
});
|
|
148
|
-
usedErrors.add(err.memory.id);
|
|
149
|
-
usedLearnings.add(best.memory.id);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return pairs;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Augment an existing DPO export with synthetic pairs.
|
|
158
|
-
*
|
|
159
|
-
* @param {object} dpoExport - Output from exportDpoFromMemories()
|
|
160
|
-
* @param {object} [options]
|
|
161
|
-
* @param {boolean} [options.scenarioVariations=true] - Generate prompt variations
|
|
162
|
-
* @param {boolean} [options.contrastivePairing=true] - Pair unmatched errors/learnings
|
|
163
|
-
* @param {boolean} [options.principleExtraction=true] - Extract abstract principles
|
|
164
|
-
* @param {boolean} [options.skipProCheck=false] - Skip Pro check (for testing)
|
|
165
|
-
* @param {Function} [options.requireProFn=requirePro] - Injectable Pro gate helper for testing
|
|
166
|
-
* @returns {{ originalPairs: number, syntheticPairs: number, totalPairs: number, pairs: object[], principles: object[] }}
|
|
167
|
-
*/
|
|
168
|
-
function augmentDpoExport(dpoExport, options = {}) {
|
|
169
|
-
const {
|
|
170
|
-
scenarioVariations = true,
|
|
171
|
-
contrastivePairing = true,
|
|
172
|
-
principleExtraction = true,
|
|
173
|
-
skipProCheck = false,
|
|
174
|
-
requireProFn = requirePro,
|
|
175
|
-
} = options;
|
|
176
|
-
|
|
177
|
-
// Pro gate (unless testing)
|
|
178
|
-
if (!skipProCheck && !requireProFn('dpo-synthesis')) {
|
|
179
|
-
return {
|
|
180
|
-
originalPairs: dpoExport.pairs?.length || 0,
|
|
181
|
-
syntheticPairs: 0,
|
|
182
|
-
totalPairs: dpoExport.pairs?.length || 0,
|
|
183
|
-
pairs: dpoExport.pairs || [],
|
|
184
|
-
principles: [],
|
|
185
|
-
proRequired: true,
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
const originalPairs = dpoExport.pairs || [];
|
|
190
|
-
const syntheticPairs = [];
|
|
191
|
-
const principles = [];
|
|
192
|
-
|
|
193
|
-
// 1. Scenario variations from existing pairs
|
|
194
|
-
if (scenarioVariations) {
|
|
195
|
-
for (const pair of originalPairs) {
|
|
196
|
-
const variations = generateScenarioVariations(pair);
|
|
197
|
-
syntheticPairs.push(...variations);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// 2. Contrastive pairing from unpaired errors/learnings
|
|
202
|
-
if (contrastivePairing) {
|
|
203
|
-
const contrastive = buildContrastivePairs(
|
|
204
|
-
dpoExport.unpairedErrors || [],
|
|
205
|
-
dpoExport.unpairedLearnings || [],
|
|
206
|
-
);
|
|
207
|
-
syntheticPairs.push(...contrastive);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
// 3. Principle extraction
|
|
211
|
-
if (principleExtraction) {
|
|
212
|
-
for (const pair of originalPairs) {
|
|
213
|
-
principles.push(extractPrinciple(pair));
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
const allPairs = [...originalPairs, ...syntheticPairs];
|
|
218
|
-
|
|
219
|
-
return {
|
|
220
|
-
originalPairs: originalPairs.length,
|
|
221
|
-
syntheticPairs: syntheticPairs.length,
|
|
222
|
-
totalPairs: allPairs.length,
|
|
223
|
-
pairs: allPairs,
|
|
224
|
-
principles,
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
module.exports = {
|
|
229
|
-
augmentDpoExport,
|
|
230
|
-
extractPrinciple,
|
|
231
|
-
generateScenarioVariations,
|
|
232
|
-
buildContrastivePairs,
|
|
233
|
-
truncate,
|
|
234
|
-
};
|
package/scripts/tessl-export.js
DELETED
|
@@ -1,369 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
const fs = require('node:fs');
|
|
5
|
-
const os = require('node:os');
|
|
6
|
-
const path = require('node:path');
|
|
7
|
-
const { ensureDir } = require('./fs-utils');
|
|
8
|
-
|
|
9
|
-
const ROOT = path.join(__dirname, '..');
|
|
10
|
-
const DEFAULT_CONFIG_PATH = path.join(ROOT, 'config', 'tessl-tiles.json');
|
|
11
|
-
const DEFAULT_OUT_DIR = path.join(ROOT, '.artifacts', 'tessl');
|
|
12
|
-
const DEFAULT_SKILLS_DIR = path.join(ROOT, 'skills');
|
|
13
|
-
|
|
14
|
-
function readJson(filePath) {
|
|
15
|
-
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
function cleanDir(dirPath) {
|
|
20
|
-
fs.rmSync(dirPath, { recursive: true, force: true });
|
|
21
|
-
ensureDir(dirPath);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function stripQuotes(value) {
|
|
25
|
-
const trimmed = String(value || '').trim();
|
|
26
|
-
if (
|
|
27
|
-
(trimmed.startsWith('"') && trimmed.endsWith('"')) ||
|
|
28
|
-
(trimmed.startsWith('\'') && trimmed.endsWith('\''))
|
|
29
|
-
) {
|
|
30
|
-
return trimmed.slice(1, -1);
|
|
31
|
-
}
|
|
32
|
-
return trimmed;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function parseFrontmatter(content) {
|
|
36
|
-
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
37
|
-
if (!match) return null;
|
|
38
|
-
|
|
39
|
-
const lines = match[1].split('\n');
|
|
40
|
-
const frontmatter = {};
|
|
41
|
-
|
|
42
|
-
for (let index = 0; index < lines.length; index++) {
|
|
43
|
-
const line = lines[index];
|
|
44
|
-
const keyMatch = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
|
|
45
|
-
if (!keyMatch) continue;
|
|
46
|
-
|
|
47
|
-
const key = keyMatch[1];
|
|
48
|
-
const rawValue = keyMatch[2];
|
|
49
|
-
|
|
50
|
-
if (rawValue === '>' || rawValue === '|') {
|
|
51
|
-
const folded = rawValue === '>';
|
|
52
|
-
const chunks = [];
|
|
53
|
-
let nextIndex = index + 1;
|
|
54
|
-
|
|
55
|
-
while (nextIndex < lines.length) {
|
|
56
|
-
const continuation = lines[nextIndex];
|
|
57
|
-
if (/^[A-Za-z0-9_-]+:\s*/.test(continuation)) break;
|
|
58
|
-
if (!continuation.startsWith(' ')) break;
|
|
59
|
-
chunks.push(continuation.trim());
|
|
60
|
-
nextIndex++;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
frontmatter[key] = folded ? chunks.join(' ').trim() : chunks.join('\n').trim();
|
|
64
|
-
index = nextIndex - 1;
|
|
65
|
-
continue;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (rawValue === '') {
|
|
69
|
-
const values = [];
|
|
70
|
-
let nextIndex = index + 1;
|
|
71
|
-
|
|
72
|
-
while (nextIndex < lines.length) {
|
|
73
|
-
const continuation = lines[nextIndex];
|
|
74
|
-
if (!continuation.startsWith(' - ')) break;
|
|
75
|
-
values.push(stripQuotes(continuation.slice(4)));
|
|
76
|
-
nextIndex++;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
frontmatter[key] = values;
|
|
80
|
-
index = nextIndex - 1;
|
|
81
|
-
continue;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
frontmatter[key] = stripQuotes(rawValue);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return frontmatter;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function parseSkillMetadata(skillDir) {
|
|
91
|
-
const skillPath = path.join(skillDir, 'SKILL.md');
|
|
92
|
-
if (!fs.existsSync(skillPath)) {
|
|
93
|
-
throw new Error(`Missing SKILL.md in ${skillDir}`);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const content = fs.readFileSync(skillPath, 'utf8');
|
|
97
|
-
const frontmatter = parseFrontmatter(content);
|
|
98
|
-
|
|
99
|
-
if (!frontmatter || !frontmatter.name || !frontmatter.description) {
|
|
100
|
-
throw new Error(`Invalid SKILL frontmatter in ${skillPath}`);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return {
|
|
104
|
-
dirName: path.basename(skillDir),
|
|
105
|
-
skillPath,
|
|
106
|
-
frontmatter,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function loadTileConfig(configPath = DEFAULT_CONFIG_PATH) {
|
|
111
|
-
const config = readJson(configPath);
|
|
112
|
-
|
|
113
|
-
if (!Array.isArray(config.tiles) || config.tiles.length === 0) {
|
|
114
|
-
throw new Error('config/tessl-tiles.json must declare at least one tile');
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return config;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function resolveWorkspace(config, overrideWorkspace) {
|
|
121
|
-
return overrideWorkspace || process.env.TESSL_WORKSPACE || config.defaultWorkspace || 'thumbgate';
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function buildTileManifest(tile, workspace, packageVersion, skillEntries) {
|
|
125
|
-
const skills = {};
|
|
126
|
-
|
|
127
|
-
for (const skill of skillEntries) {
|
|
128
|
-
skills[skill.dirName] = {
|
|
129
|
-
path: `skills/${skill.dirName}/SKILL.md`,
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return {
|
|
134
|
-
name: `${workspace}/${tile.tileName}`,
|
|
135
|
-
version: packageVersion,
|
|
136
|
-
summary: tile.summary,
|
|
137
|
-
private: Boolean(tile.private),
|
|
138
|
-
docs: 'index.md',
|
|
139
|
-
skills,
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function renderTileDocs(tile, manifest, skillEntries, proofLinks) {
|
|
144
|
-
const skillNames = skillEntries.map((entry) => `\`${entry.frontmatter.name}\``).join(', ');
|
|
145
|
-
const installCommand = `tessl install ${manifest.name}`;
|
|
146
|
-
|
|
147
|
-
return [
|
|
148
|
-
`# ${manifest.name}`,
|
|
149
|
-
'',
|
|
150
|
-
tile.summary,
|
|
151
|
-
'',
|
|
152
|
-
'## Included skills',
|
|
153
|
-
'',
|
|
154
|
-
`- ${skillNames}`,
|
|
155
|
-
'',
|
|
156
|
-
'## Install',
|
|
157
|
-
'',
|
|
158
|
-
'```bash',
|
|
159
|
-
installCommand,
|
|
160
|
-
'```',
|
|
161
|
-
'',
|
|
162
|
-
'## Why this tile exists',
|
|
163
|
-
'',
|
|
164
|
-
'ThumbGate uses thumbs up and thumbs down feedback to build structured memory, generate prevention rules, and block repeated agent mistakes before execution.',
|
|
165
|
-
'',
|
|
166
|
-
'## Proof',
|
|
167
|
-
'',
|
|
168
|
-
`- Verification evidence: ${proofLinks.verificationEvidence}`,
|
|
169
|
-
`- Compatibility report: ${proofLinks.compatibilityReport}`,
|
|
170
|
-
`- Automation report: ${proofLinks.automationReport}`,
|
|
171
|
-
'',
|
|
172
|
-
'## Source of truth',
|
|
173
|
-
'',
|
|
174
|
-
...skillEntries.map((entry) => `- Generated from \`skills/${entry.dirName}/SKILL.md\``),
|
|
175
|
-
'',
|
|
176
|
-
].join('\n');
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
function exportTiles({
|
|
180
|
-
configPath = DEFAULT_CONFIG_PATH,
|
|
181
|
-
outDir = DEFAULT_OUT_DIR,
|
|
182
|
-
workspace,
|
|
183
|
-
clean = true,
|
|
184
|
-
skillsDir = DEFAULT_SKILLS_DIR,
|
|
185
|
-
} = {}) {
|
|
186
|
-
const config = loadTileConfig(configPath);
|
|
187
|
-
const packageJson = readJson(path.join(ROOT, 'package.json'));
|
|
188
|
-
const activeWorkspace = resolveWorkspace(config, workspace);
|
|
189
|
-
|
|
190
|
-
if (clean) {
|
|
191
|
-
cleanDir(outDir);
|
|
192
|
-
} else {
|
|
193
|
-
ensureDir(outDir);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const results = [];
|
|
197
|
-
|
|
198
|
-
for (const tile of config.tiles) {
|
|
199
|
-
if (!Array.isArray(tile.sourceSkills) || tile.sourceSkills.length === 0) {
|
|
200
|
-
throw new Error(`Tile ${tile.id || tile.tileName} must declare sourceSkills`);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
const tileDir = path.join(outDir, tile.tileName);
|
|
204
|
-
const tileSkillsDir = path.join(tileDir, 'skills');
|
|
205
|
-
ensureDir(tileSkillsDir);
|
|
206
|
-
|
|
207
|
-
const skillEntries = tile.sourceSkills.map((skillName) => {
|
|
208
|
-
const sourceDir = path.join(skillsDir, skillName);
|
|
209
|
-
const destinationDir = path.join(tileSkillsDir, skillName);
|
|
210
|
-
const metadata = parseSkillMetadata(sourceDir);
|
|
211
|
-
|
|
212
|
-
fs.cpSync(sourceDir, destinationDir, { recursive: true });
|
|
213
|
-
return metadata;
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
const manifest = buildTileManifest(tile, activeWorkspace, packageJson.version, skillEntries);
|
|
217
|
-
const docs = renderTileDocs(tile, manifest, skillEntries, config.proofLinks);
|
|
218
|
-
|
|
219
|
-
fs.writeFileSync(path.join(tileDir, 'tile.json'), `${JSON.stringify(manifest, null, 2)}\n`);
|
|
220
|
-
fs.writeFileSync(path.join(tileDir, 'index.md'), `${docs}\n`);
|
|
221
|
-
|
|
222
|
-
results.push({
|
|
223
|
-
id: tile.id,
|
|
224
|
-
tileName: tile.tileName,
|
|
225
|
-
manifestName: manifest.name,
|
|
226
|
-
directory: tileDir,
|
|
227
|
-
skillCount: skillEntries.length,
|
|
228
|
-
skills: skillEntries.map((entry) => entry.dirName),
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return results;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
function verifyTiles(options = {}) {
|
|
236
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'thumbgate-tessl-verify-'));
|
|
237
|
-
|
|
238
|
-
try {
|
|
239
|
-
const results = exportTiles({
|
|
240
|
-
...options,
|
|
241
|
-
outDir: tempDir,
|
|
242
|
-
clean: true,
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
for (const result of results) {
|
|
246
|
-
const tileDir = path.join(tempDir, result.tileName);
|
|
247
|
-
const manifestPath = path.join(tileDir, 'tile.json');
|
|
248
|
-
const docsPath = path.join(tileDir, 'index.md');
|
|
249
|
-
const manifest = readJson(manifestPath);
|
|
250
|
-
const docs = fs.readFileSync(docsPath, 'utf8');
|
|
251
|
-
|
|
252
|
-
if (!manifest.name.includes('/')) {
|
|
253
|
-
throw new Error(`${result.tileName} manifest must use workspace/tile format`);
|
|
254
|
-
}
|
|
255
|
-
if (!manifest.version) {
|
|
256
|
-
throw new Error(`${result.tileName} manifest is missing version`);
|
|
257
|
-
}
|
|
258
|
-
if (manifest.docs !== 'index.md') {
|
|
259
|
-
throw new Error(`${result.tileName} manifest must point docs to index.md`);
|
|
260
|
-
}
|
|
261
|
-
if (!manifest.skills || Object.keys(manifest.skills).length === 0) {
|
|
262
|
-
throw new Error(`${result.tileName} manifest must declare skills`);
|
|
263
|
-
}
|
|
264
|
-
if (!docs.includes('Verification evidence')) {
|
|
265
|
-
throw new Error(`${result.tileName} docs are missing proof links`);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
for (const [skillName, spec] of Object.entries(manifest.skills)) {
|
|
269
|
-
const exportedSkillPath = path.join(tileDir, spec.path);
|
|
270
|
-
if (!fs.existsSync(exportedSkillPath)) {
|
|
271
|
-
throw new Error(`${result.tileName} is missing exported skill ${skillName}`);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
const skillFrontmatter = parseFrontmatter(fs.readFileSync(exportedSkillPath, 'utf8'));
|
|
275
|
-
if (!skillFrontmatter || !skillFrontmatter.name || !skillFrontmatter.description) {
|
|
276
|
-
throw new Error(`${result.tileName} exported skill ${skillName} has invalid frontmatter`);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
return {
|
|
282
|
-
ok: true,
|
|
283
|
-
tileCount: results.length,
|
|
284
|
-
tiles: results.map((result) => result.manifestName),
|
|
285
|
-
};
|
|
286
|
-
} finally {
|
|
287
|
-
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
function parseArgs(argv) {
|
|
292
|
-
const args = {
|
|
293
|
-
command: 'export',
|
|
294
|
-
outDir: DEFAULT_OUT_DIR,
|
|
295
|
-
workspace: null,
|
|
296
|
-
clean: true,
|
|
297
|
-
json: false,
|
|
298
|
-
};
|
|
299
|
-
|
|
300
|
-
for (const token of argv) {
|
|
301
|
-
if (token === 'export' || token === 'verify') {
|
|
302
|
-
args.command = token;
|
|
303
|
-
} else if (token === '--json') {
|
|
304
|
-
args.json = true;
|
|
305
|
-
} else if (token === '--no-clean') {
|
|
306
|
-
args.clean = false;
|
|
307
|
-
} else if (token.startsWith('--out-dir=')) {
|
|
308
|
-
args.outDir = path.resolve(token.slice('--out-dir='.length));
|
|
309
|
-
} else if (token.startsWith('--workspace=')) {
|
|
310
|
-
args.workspace = token.slice('--workspace='.length);
|
|
311
|
-
} else {
|
|
312
|
-
throw new Error(`Unsupported argument: ${token}`);
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
return args;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
function printResults(result, emitJson) {
|
|
320
|
-
if (emitJson) {
|
|
321
|
-
console.log(JSON.stringify(result, null, 2));
|
|
322
|
-
return;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
if (Array.isArray(result)) {
|
|
326
|
-
console.log(`Exported ${result.length} Tessl tile(s):`);
|
|
327
|
-
for (const tile of result) {
|
|
328
|
-
console.log(`- ${tile.manifestName} -> ${tile.directory}`);
|
|
329
|
-
}
|
|
330
|
-
return;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
console.log(`Verified ${result.tileCount} Tessl tile(s): ${result.tiles.join(', ')}`);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
function runCli(argv = process.argv.slice(2)) {
|
|
337
|
-
const args = parseArgs(argv);
|
|
338
|
-
const action = args.command === 'verify' ? verifyTiles : exportTiles;
|
|
339
|
-
const result = action({
|
|
340
|
-
outDir: args.outDir,
|
|
341
|
-
workspace: args.workspace,
|
|
342
|
-
clean: args.clean,
|
|
343
|
-
});
|
|
344
|
-
printResults(result, args.json);
|
|
345
|
-
return result;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
if (require.main === module) {
|
|
349
|
-
try {
|
|
350
|
-
runCli();
|
|
351
|
-
} catch (error) {
|
|
352
|
-
console.error(error.message || String(error));
|
|
353
|
-
process.exit(1);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
module.exports = {
|
|
358
|
-
DEFAULT_CONFIG_PATH,
|
|
359
|
-
DEFAULT_OUT_DIR,
|
|
360
|
-
buildTileManifest,
|
|
361
|
-
exportTiles,
|
|
362
|
-
loadTileConfig,
|
|
363
|
-
parseFrontmatter,
|
|
364
|
-
parseSkillMetadata,
|
|
365
|
-
renderTileDocs,
|
|
366
|
-
resolveWorkspace,
|
|
367
|
-
runCli,
|
|
368
|
-
verifyTiles,
|
|
369
|
-
};
|