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
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Hallucination Detector — claim verification, confidence-weighted gates,
|
|
6
|
-
* retrieval-grounded verification.
|
|
7
|
-
*
|
|
8
|
-
* Turns ThumbGate from "block known-bad patterns" into "detect and block
|
|
9
|
-
* hallucinated claims" using 3 techniques from hallucination detection research.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
const { constructContextPack } = require('./contextfs');
|
|
13
|
-
const { matchSkillPacks } = require('./skill-packs');
|
|
14
|
-
|
|
15
|
-
// ---------------------------------------------------------------------------
|
|
16
|
-
// 1. Claim Decomposition & Verification
|
|
17
|
-
// ---------------------------------------------------------------------------
|
|
18
|
-
|
|
19
|
-
const CLAIM_PATTERNS = [
|
|
20
|
-
{ pattern: /\b(?:deployed|shipped|live|released)\b/i, type: 'deployment', verifyWith: ['health_check', 'version_match'] },
|
|
21
|
-
{ pattern: /\b(?:tests?\s+pass|all\s+tests?\s+(?:pass|green))\b/i, type: 'test_result', verifyWith: ['test_output', 'exit_code'] },
|
|
22
|
-
{ pattern: /\b(?:merged|PR\s+merged)\b/i, type: 'pr_merge', verifyWith: ['pr_state', 'ci_status'] },
|
|
23
|
-
{ pattern: /\b(?:fixed|resolved|bug\s+fix)\b/i, type: 'fix_claim', verifyWith: ['test_evidence', 'reproduction_check'] },
|
|
24
|
-
{ pattern: /\b(?:published|npm\s+publish)\b/i, type: 'publish', verifyWith: ['registry_check', 'version_match'] },
|
|
25
|
-
{ pattern: /\b(?:no\s+(?:errors?|failures?|issues?))\b/i, type: 'clean_state', verifyWith: ['log_check', 'status_check'] },
|
|
26
|
-
];
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Decompose agent output into verifiable sub-claims.
|
|
30
|
-
* Returns array of { claim, type, verifyWith, text }.
|
|
31
|
-
*/
|
|
32
|
-
function decomposeClaims(agentOutput) {
|
|
33
|
-
const text = String(agentOutput || '');
|
|
34
|
-
if (!text.trim()) return [];
|
|
35
|
-
|
|
36
|
-
const claims = [];
|
|
37
|
-
for (const cp of CLAIM_PATTERNS) {
|
|
38
|
-
cp.pattern.lastIndex = 0;
|
|
39
|
-
const matches = text.match(cp.pattern);
|
|
40
|
-
if (matches) {
|
|
41
|
-
for (const match of matches) {
|
|
42
|
-
// Extract surrounding sentence for context
|
|
43
|
-
const idx = text.indexOf(match);
|
|
44
|
-
const start = Math.max(0, text.lastIndexOf('.', idx) + 1);
|
|
45
|
-
const end = text.indexOf('.', idx + match.length);
|
|
46
|
-
const sentence = text.slice(start, end > idx ? end + 1 : undefined).trim().slice(0, 200);
|
|
47
|
-
|
|
48
|
-
claims.push({
|
|
49
|
-
claim: match,
|
|
50
|
-
type: cp.type,
|
|
51
|
-
verifyWith: cp.verifyWith,
|
|
52
|
-
context: sentence,
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return claims;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Check a decomposed claim against available evidence.
|
|
63
|
-
* Evidence is a map of { evidence_type: boolean_or_string }.
|
|
64
|
-
*/
|
|
65
|
-
function verifyClaim(claim, evidence) {
|
|
66
|
-
const missing = [];
|
|
67
|
-
const verified = [];
|
|
68
|
-
|
|
69
|
-
for (const req of claim.verifyWith) {
|
|
70
|
-
if (evidence[req] === true || (typeof evidence[req] === 'string' && evidence[req].length > 0)) {
|
|
71
|
-
verified.push(req);
|
|
72
|
-
} else {
|
|
73
|
-
missing.push(req);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const isVerified = missing.length === 0;
|
|
78
|
-
return {
|
|
79
|
-
claim: claim.claim,
|
|
80
|
-
type: claim.type,
|
|
81
|
-
verified: isVerified,
|
|
82
|
-
verifiedEvidence: verified,
|
|
83
|
-
missingEvidence: missing,
|
|
84
|
-
confidence: claim.verifyWith.length > 0 ? Math.round((verified.length / claim.verifyWith.length) * 100) : 0,
|
|
85
|
-
verdict: isVerified ? 'grounded' : missing.length === claim.verifyWith.length ? 'hallucination' : 'partial',
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// ---------------------------------------------------------------------------
|
|
90
|
-
// 2. Confidence-Weighted Gate Decisions
|
|
91
|
-
// ---------------------------------------------------------------------------
|
|
92
|
-
|
|
93
|
-
const CONFIDENCE_THRESHOLDS = {
|
|
94
|
-
none: { action: 'block', minSamples: 0, maxSamples: 0 },
|
|
95
|
-
low: { action: 'block', minSamples: 1, maxSamples: 4 },
|
|
96
|
-
medium: { action: 'warn', minSamples: 5, maxSamples: 19 },
|
|
97
|
-
high: { action: 'allow', minSamples: 20, maxSamples: Infinity },
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Determine gate action based on Thompson Sampling confidence tier.
|
|
102
|
-
* Low confidence = stricter (block), high confidence = lenient (allow).
|
|
103
|
-
*/
|
|
104
|
-
function confidenceWeightedDecision({ confidence, reliability, samples }) {
|
|
105
|
-
let tier = 'none';
|
|
106
|
-
const s = samples || 0;
|
|
107
|
-
|
|
108
|
-
if (s === 0) tier = 'none';
|
|
109
|
-
else if (s <= 4) tier = 'low';
|
|
110
|
-
else if (s <= 19) tier = 'medium';
|
|
111
|
-
else tier = 'high';
|
|
112
|
-
|
|
113
|
-
const threshold = CONFIDENCE_THRESHOLDS[tier];
|
|
114
|
-
const rel = typeof reliability === 'number' ? reliability : 0.5;
|
|
115
|
-
|
|
116
|
-
// Override: even high-confidence, if reliability < 0.3 → block
|
|
117
|
-
let action = threshold.action;
|
|
118
|
-
if (rel < 0.3) action = 'block';
|
|
119
|
-
else if (rel < 0.5 && tier === 'high') action = 'warn';
|
|
120
|
-
|
|
121
|
-
return {
|
|
122
|
-
tier,
|
|
123
|
-
action,
|
|
124
|
-
reliability: Math.round(rel * 1000) / 1000,
|
|
125
|
-
samples: s,
|
|
126
|
-
reasoning: `${tier} confidence (${s} samples, ${Math.round(rel * 100)}% reliability) → ${action}`,
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// ---------------------------------------------------------------------------
|
|
131
|
-
// 3. Retrieval-Grounded Verification
|
|
132
|
-
// ---------------------------------------------------------------------------
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Check if a proposed action contradicts recalled prevention rules.
|
|
136
|
-
* Retrieves relevant context and scans for contradictions.
|
|
137
|
-
*
|
|
138
|
-
* Returns { grounded, contradictions, relevantRules, groundingScore }.
|
|
139
|
-
*/
|
|
140
|
-
function retrievalGroundedCheck(proposedAction, { maxItems = 5, maxChars = 3000 } = {}) {
|
|
141
|
-
const actionText = String(proposedAction || '').toLowerCase();
|
|
142
|
-
if (!actionText.trim()) return { grounded: true, contradictions: [], relevantRules: [], groundingScore: 100 };
|
|
143
|
-
|
|
144
|
-
// Retrieve relevant context
|
|
145
|
-
let pack;
|
|
146
|
-
try {
|
|
147
|
-
pack = constructContextPack({ query: proposedAction, maxItems, maxChars, namespaces: ['rules', 'memoryError'] });
|
|
148
|
-
} catch {
|
|
149
|
-
return { grounded: true, contradictions: [], relevantRules: [], groundingScore: 100 };
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const contradictions = [];
|
|
153
|
-
const relevantRules = [];
|
|
154
|
-
|
|
155
|
-
for (const item of pack.items) {
|
|
156
|
-
const content = ((item.structuredContext && item.structuredContext.rawContent) || '').toLowerCase();
|
|
157
|
-
const title = (item.title || '').toLowerCase();
|
|
158
|
-
|
|
159
|
-
// Check for NEVER/ALWAYS rules that contradict the action
|
|
160
|
-
const neverMatches = content.match(/never\s+(.{10,80})/gi) || [];
|
|
161
|
-
for (const neverRule of neverMatches) {
|
|
162
|
-
const ruleAction = neverRule.replace(/^never\s+/i, '').trim();
|
|
163
|
-
// Check if the proposed action contains what the rule says never to do
|
|
164
|
-
const ruleTokens = ruleAction.split(/\s+/).filter((t) => t.length > 3);
|
|
165
|
-
const matchCount = ruleTokens.filter((t) => actionText.includes(t)).length;
|
|
166
|
-
if (matchCount >= 2) {
|
|
167
|
-
contradictions.push({
|
|
168
|
-
rule: neverRule.trim(),
|
|
169
|
-
source: item.title,
|
|
170
|
-
matchStrength: Math.round((matchCount / ruleTokens.length) * 100),
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Track all relevant rules
|
|
176
|
-
if (item.score > 0) {
|
|
177
|
-
relevantRules.push({ title: item.title, score: item.score, namespace: item.namespace });
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const groundingScore = contradictions.length === 0 ? 100 : Math.max(0, 100 - contradictions.length * 25);
|
|
182
|
-
|
|
183
|
-
return {
|
|
184
|
-
grounded: contradictions.length === 0,
|
|
185
|
-
contradictions,
|
|
186
|
-
relevantRules,
|
|
187
|
-
groundingScore,
|
|
188
|
-
packItemCount: pack.items.length,
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Full hallucination check: decompose claims + verify + ground against rules.
|
|
194
|
-
* Returns comprehensive report.
|
|
195
|
-
*/
|
|
196
|
-
function fullHallucinationCheck(agentOutput, evidence = {}) {
|
|
197
|
-
const claims = decomposeClaims(agentOutput);
|
|
198
|
-
const claimResults = claims.map((c) => verifyClaim(c, evidence));
|
|
199
|
-
const grounding = retrievalGroundedCheck(agentOutput);
|
|
200
|
-
|
|
201
|
-
const verifiedCount = claimResults.filter((r) => r.verified).length;
|
|
202
|
-
const hallucinationCount = claimResults.filter((r) => r.verdict === 'hallucination').length;
|
|
203
|
-
const totalClaims = claimResults.length;
|
|
204
|
-
|
|
205
|
-
return {
|
|
206
|
-
claims: claimResults,
|
|
207
|
-
grounding,
|
|
208
|
-
summary: {
|
|
209
|
-
totalClaims,
|
|
210
|
-
verified: verifiedCount,
|
|
211
|
-
hallucinated: hallucinationCount,
|
|
212
|
-
partial: totalClaims - verifiedCount - hallucinationCount,
|
|
213
|
-
claimPassRate: totalClaims > 0 ? Math.round((verifiedCount / totalClaims) * 1000) / 10 : 100,
|
|
214
|
-
groundingScore: grounding.groundingScore,
|
|
215
|
-
overallVerdict: hallucinationCount > 0 ? 'hallucination_detected' : (grounding.grounded ? 'grounded' : 'contradiction_detected'),
|
|
216
|
-
},
|
|
217
|
-
checkedAt: new Date().toISOString(),
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
module.exports = {
|
|
222
|
-
CLAIM_PATTERNS, CONFIDENCE_THRESHOLDS,
|
|
223
|
-
decomposeClaims, verifyClaim,
|
|
224
|
-
confidenceWeightedDecision,
|
|
225
|
-
retrievalGroundedCheck, fullHallucinationCheck,
|
|
226
|
-
};
|
package/scripts/hf-papers.js
DELETED
|
@@ -1,317 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { URL, URLSearchParams } = require('node:url');
|
|
4
|
-
const {
|
|
5
|
-
NAMESPACES,
|
|
6
|
-
upsertContextObject,
|
|
7
|
-
recordProvenance,
|
|
8
|
-
constructTemplatedPack,
|
|
9
|
-
} = require('./contextfs');
|
|
10
|
-
|
|
11
|
-
const DEFAULT_HF_PAPERS_API_BASE = process.env.HF_PAPERS_API_BASE || 'https://huggingface.co/api';
|
|
12
|
-
const DEFAULT_LIMIT = 5;
|
|
13
|
-
|
|
14
|
-
function normalizeAuthors(authors) {
|
|
15
|
-
if (!Array.isArray(authors)) return [];
|
|
16
|
-
return authors
|
|
17
|
-
.map((author) => {
|
|
18
|
-
if (typeof author === 'string') return author.trim();
|
|
19
|
-
if (author && typeof author.name === 'string') return author.name.trim();
|
|
20
|
-
return '';
|
|
21
|
-
})
|
|
22
|
-
.filter(Boolean);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function normalizeTags(tags) {
|
|
26
|
-
if (!Array.isArray(tags)) return [];
|
|
27
|
-
return [...new Set(tags
|
|
28
|
-
.map((tag) => {
|
|
29
|
-
if (typeof tag === 'string') return tag.trim();
|
|
30
|
-
if (tag && typeof tag.label === 'string') return tag.label.trim();
|
|
31
|
-
if (tag && typeof tag.name === 'string') return tag.name.trim();
|
|
32
|
-
return '';
|
|
33
|
-
})
|
|
34
|
-
.filter(Boolean))];
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function normalizePaper(record = {}) {
|
|
38
|
-
const paper = record && typeof record.paper === 'object' ? record.paper : record;
|
|
39
|
-
const paperId = String(
|
|
40
|
-
paper.id
|
|
41
|
-
|| paper.paper_id
|
|
42
|
-
|| paper.paperId
|
|
43
|
-
|| paper.arxiv_id
|
|
44
|
-
|| paper.arxivId
|
|
45
|
-
|| record.id
|
|
46
|
-
|| record.paper_id
|
|
47
|
-
|| record.paperId
|
|
48
|
-
|| record.arxiv_id
|
|
49
|
-
|| record.arxivId
|
|
50
|
-
|| ''
|
|
51
|
-
).trim();
|
|
52
|
-
const title = String(
|
|
53
|
-
paper.title
|
|
54
|
-
|| record.title
|
|
55
|
-
|| (paperId ? `Paper ${paperId}` : 'Untitled paper')
|
|
56
|
-
).trim();
|
|
57
|
-
const summary = String(
|
|
58
|
-
paper.summary
|
|
59
|
-
|| paper.abstract
|
|
60
|
-
|| record.summary
|
|
61
|
-
|| record.abstract
|
|
62
|
-
|| ''
|
|
63
|
-
).trim();
|
|
64
|
-
const url = String(
|
|
65
|
-
paper.url
|
|
66
|
-
|| paper.paper_url
|
|
67
|
-
|| record.url
|
|
68
|
-
|| record.paper_url
|
|
69
|
-
|| (paperId ? `https://arxiv.org/abs/${paperId}` : '')
|
|
70
|
-
).trim();
|
|
71
|
-
|
|
72
|
-
return {
|
|
73
|
-
paperId,
|
|
74
|
-
title,
|
|
75
|
-
summary,
|
|
76
|
-
url: url || null,
|
|
77
|
-
authors: normalizeAuthors(paper.authors || record.authors),
|
|
78
|
-
tags: normalizeTags(paper.tags || paper.categories || record.tags || record.categories),
|
|
79
|
-
publishedAt: paper.publishedAt || paper.published_at || record.publishedAt || record.published_at || null,
|
|
80
|
-
source: 'huggingface-papers',
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function extractPaperItems(payload) {
|
|
85
|
-
if (Array.isArray(payload)) return payload;
|
|
86
|
-
if (!payload || typeof payload !== 'object') return [];
|
|
87
|
-
if (Array.isArray(payload.papers)) return payload.papers;
|
|
88
|
-
if (Array.isArray(payload.items)) return payload.items;
|
|
89
|
-
if (Array.isArray(payload.results)) return payload.results;
|
|
90
|
-
if (Array.isArray(payload.dailyPapers)) return payload.dailyPapers;
|
|
91
|
-
if (payload.paper && typeof payload.paper === 'object') return [payload.paper];
|
|
92
|
-
return [];
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function buildSearchUrls({ query, limit = DEFAULT_LIMIT, baseUrl = DEFAULT_HF_PAPERS_API_BASE }) {
|
|
96
|
-
const normalizedBase = String(baseUrl || DEFAULT_HF_PAPERS_API_BASE).replace(/\/+$/, '');
|
|
97
|
-
const routes = [
|
|
98
|
-
['/daily_papers', { query, limit: String(limit) }],
|
|
99
|
-
['/papers/search', { q: query, limit: String(limit) }],
|
|
100
|
-
['/papers', { query, limit: String(limit) }],
|
|
101
|
-
];
|
|
102
|
-
|
|
103
|
-
return routes.map(([pathname, params]) => {
|
|
104
|
-
const url = new URL(`${normalizedBase}${pathname}`);
|
|
105
|
-
url.search = new URLSearchParams(params).toString();
|
|
106
|
-
return url.toString();
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
async function readJson(url, fetchImpl = global.fetch) {
|
|
111
|
-
if (typeof fetchImpl !== 'function') {
|
|
112
|
-
throw new Error('A fetch implementation is required');
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const response = await fetchImpl(url, {
|
|
116
|
-
headers: {
|
|
117
|
-
accept: 'application/json',
|
|
118
|
-
},
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
if (!response.ok) {
|
|
122
|
-
const error = new Error(`HF papers request failed: ${response.status} ${response.statusText}`);
|
|
123
|
-
error.status = response.status;
|
|
124
|
-
throw error;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return response.json();
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
async function searchPapers({
|
|
131
|
-
query,
|
|
132
|
-
limit = DEFAULT_LIMIT,
|
|
133
|
-
baseUrl = DEFAULT_HF_PAPERS_API_BASE,
|
|
134
|
-
fetchImpl = global.fetch,
|
|
135
|
-
} = {}) {
|
|
136
|
-
const normalizedQuery = String(query || '').trim();
|
|
137
|
-
if (!normalizedQuery) {
|
|
138
|
-
throw new Error('searchPapers requires query');
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const urls = buildSearchUrls({
|
|
142
|
-
query: normalizedQuery,
|
|
143
|
-
limit: Math.max(1, Number(limit) || DEFAULT_LIMIT),
|
|
144
|
-
baseUrl,
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
let lastError = null;
|
|
148
|
-
for (const url of urls) {
|
|
149
|
-
try {
|
|
150
|
-
const payload = await readJson(url, fetchImpl);
|
|
151
|
-
const papers = extractPaperItems(payload)
|
|
152
|
-
.map(normalizePaper)
|
|
153
|
-
.filter((paper) => paper.paperId || paper.title);
|
|
154
|
-
|
|
155
|
-
if (papers.length > 0) {
|
|
156
|
-
return papers.slice(0, limit);
|
|
157
|
-
}
|
|
158
|
-
} catch (error) {
|
|
159
|
-
lastError = error;
|
|
160
|
-
if (error && error.status === 404) {
|
|
161
|
-
continue;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
if (lastError) throw lastError;
|
|
167
|
-
return [];
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
function paperToMarkdown(paper) {
|
|
171
|
-
const normalized = normalizePaper(paper);
|
|
172
|
-
const lines = [
|
|
173
|
-
`# ${normalized.title}`,
|
|
174
|
-
'',
|
|
175
|
-
`Paper ID: ${normalized.paperId || 'unknown'}`,
|
|
176
|
-
`Source: ${normalized.source}`,
|
|
177
|
-
];
|
|
178
|
-
|
|
179
|
-
if (normalized.url) {
|
|
180
|
-
lines.push(`URL: ${normalized.url}`);
|
|
181
|
-
}
|
|
182
|
-
if (normalized.publishedAt) {
|
|
183
|
-
lines.push(`Published: ${normalized.publishedAt}`);
|
|
184
|
-
}
|
|
185
|
-
if (normalized.authors.length > 0) {
|
|
186
|
-
lines.push(`Authors: ${normalized.authors.join(', ')}`);
|
|
187
|
-
}
|
|
188
|
-
if (normalized.tags.length > 0) {
|
|
189
|
-
lines.push(`Tags: ${normalized.tags.join(', ')}`);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
lines.push('', '## Abstract', '', normalized.summary || 'No abstract available.', '');
|
|
193
|
-
return lines.join('\n');
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
function buildCitation(paper) {
|
|
197
|
-
return {
|
|
198
|
-
paperId: paper.paperId || null,
|
|
199
|
-
title: paper.title,
|
|
200
|
-
url: paper.url,
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
function ingestNormalizedPapers(papers, query) {
|
|
205
|
-
const ingested = papers.map((paper) => {
|
|
206
|
-
const normalizedTags = [...new Set([
|
|
207
|
-
'research',
|
|
208
|
-
'paper',
|
|
209
|
-
'hf-papers',
|
|
210
|
-
...paper.tags.map((tag) => String(tag)),
|
|
211
|
-
])].sort();
|
|
212
|
-
|
|
213
|
-
return upsertContextObject({
|
|
214
|
-
namespace: NAMESPACES.research,
|
|
215
|
-
title: `Paper: ${paper.title}`,
|
|
216
|
-
content: paperToMarkdown(paper),
|
|
217
|
-
tags: normalizedTags,
|
|
218
|
-
source: 'hf-papers',
|
|
219
|
-
metadata: {
|
|
220
|
-
provider: 'huggingface',
|
|
221
|
-
paperId: paper.paperId || null,
|
|
222
|
-
url: paper.url,
|
|
223
|
-
authors: paper.authors,
|
|
224
|
-
publishedAt: paper.publishedAt,
|
|
225
|
-
query,
|
|
226
|
-
},
|
|
227
|
-
});
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
recordProvenance({
|
|
231
|
-
type: 'hf_papers_ingested',
|
|
232
|
-
query,
|
|
233
|
-
count: ingested.length,
|
|
234
|
-
dedupedCount: ingested.filter((entry) => entry.deduped).length,
|
|
235
|
-
paperIds: papers.map((paper) => paper.paperId).filter(Boolean),
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
return ingested;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
async function ingestPaperSearch({
|
|
242
|
-
query,
|
|
243
|
-
limit = DEFAULT_LIMIT,
|
|
244
|
-
baseUrl = DEFAULT_HF_PAPERS_API_BASE,
|
|
245
|
-
fetchImpl = global.fetch,
|
|
246
|
-
searchPapersImpl = searchPapers,
|
|
247
|
-
} = {}) {
|
|
248
|
-
const papers = await searchPapersImpl({
|
|
249
|
-
query,
|
|
250
|
-
limit,
|
|
251
|
-
baseUrl,
|
|
252
|
-
fetchImpl,
|
|
253
|
-
});
|
|
254
|
-
const ingested = ingestNormalizedPapers(papers, query);
|
|
255
|
-
|
|
256
|
-
return {
|
|
257
|
-
query,
|
|
258
|
-
limit,
|
|
259
|
-
papers,
|
|
260
|
-
ingested,
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
async function buildResearchBrief({
|
|
265
|
-
query,
|
|
266
|
-
limit = DEFAULT_LIMIT,
|
|
267
|
-
template = 'research-brief',
|
|
268
|
-
baseUrl = DEFAULT_HF_PAPERS_API_BASE,
|
|
269
|
-
fetchImpl = global.fetch,
|
|
270
|
-
searchPapersImpl = searchPapers,
|
|
271
|
-
} = {}) {
|
|
272
|
-
const result = await ingestPaperSearch({
|
|
273
|
-
query,
|
|
274
|
-
limit,
|
|
275
|
-
baseUrl,
|
|
276
|
-
fetchImpl,
|
|
277
|
-
searchPapersImpl,
|
|
278
|
-
});
|
|
279
|
-
const pack = constructTemplatedPack({ template, query });
|
|
280
|
-
const citations = result.papers.map(buildCitation);
|
|
281
|
-
const brief = pack.items
|
|
282
|
-
.map((item, index) => {
|
|
283
|
-
const digest = String(item.structuredContext && item.structuredContext.rawContent || '')
|
|
284
|
-
.split('\n')
|
|
285
|
-
.slice(0, 6)
|
|
286
|
-
.join(' ')
|
|
287
|
-
.trim();
|
|
288
|
-
return `${index + 1}. ${item.title} ${digest}`.trim();
|
|
289
|
-
})
|
|
290
|
-
.join('\n');
|
|
291
|
-
|
|
292
|
-
return {
|
|
293
|
-
query,
|
|
294
|
-
limit,
|
|
295
|
-
source: 'huggingface-papers',
|
|
296
|
-
template,
|
|
297
|
-
ingestedCount: result.ingested.length,
|
|
298
|
-
packId: pack.packId,
|
|
299
|
-
citations,
|
|
300
|
-
brief,
|
|
301
|
-
pack,
|
|
302
|
-
};
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
module.exports = {
|
|
306
|
-
DEFAULT_HF_PAPERS_API_BASE,
|
|
307
|
-
buildResearchBrief,
|
|
308
|
-
buildSearchUrls,
|
|
309
|
-
extractPaperItems,
|
|
310
|
-
ingestNormalizedPapers,
|
|
311
|
-
ingestPaperSearch,
|
|
312
|
-
normalizeAuthors,
|
|
313
|
-
normalizePaper,
|
|
314
|
-
normalizeTags,
|
|
315
|
-
paperToMarkdown,
|
|
316
|
-
searchPapers,
|
|
317
|
-
};
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Claude Code UserPromptSubmit hook — auto-captures thumbs up/down feedback
|
|
3
|
-
# Triggered on every user message. Only acts on feedback signals.
|
|
4
|
-
# Shows full verbose output with storage paths, memory IDs, and stats.
|
|
5
|
-
|
|
6
|
-
PROMPT="$CLAUDE_USER_PROMPT"
|
|
7
|
-
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
8
|
-
CAPTURE="$SCRIPT_DIR/../.claude/scripts/feedback/capture-feedback.js"
|
|
9
|
-
PROMPT_GUARD="$SCRIPT_DIR/prompt-guard.js"
|
|
10
|
-
ACTIVE_CWD="${CLAUDE_PROJECT_DIR:-${PWD:-$(pwd)}}"
|
|
11
|
-
FEEDBACK_DIR="$(node -e "const path = require('path'); const { resolveFeedbackDir } = require(path.join(process.argv[1], 'feedback-paths.js')); process.stdout.write(resolveFeedbackDir({ cwd: process.argv[2] || process.cwd(), feedbackDir: process.env.THUMBGATE_FEEDBACK_DIR || undefined }));" "$SCRIPT_DIR" "$ACTIVE_CWD" 2>/dev/null)"
|
|
12
|
-
if [ -z "$FEEDBACK_DIR" ]; then
|
|
13
|
-
FEEDBACK_DIR="${THUMBGATE_FEEDBACK_DIR:-$ACTIVE_CWD/.thumbgate}"
|
|
14
|
-
fi
|
|
15
|
-
FEEDBACK_LOG="$FEEDBACK_DIR/feedback-log.jsonl"
|
|
16
|
-
MEMORY_LOG="$FEEDBACK_DIR/memory-log.jsonl"
|
|
17
|
-
|
|
18
|
-
# Record the latest user prompt so statusline thumbs can distill lessons
|
|
19
|
-
# from recent conversation even when the click itself has no body payload.
|
|
20
|
-
THUMBGATE_CONVERSATION_TEXT="$PROMPT" node -e "
|
|
21
|
-
const { recordConversationEntry } = require(process.argv[1]);
|
|
22
|
-
recordConversationEntry({
|
|
23
|
-
author: 'user',
|
|
24
|
-
text: process.env.THUMBGATE_CONVERSATION_TEXT || '',
|
|
25
|
-
source: 'claude_user_prompt',
|
|
26
|
-
});
|
|
27
|
-
" "$SCRIPT_DIR/feedback-history-distiller.js" 2>/dev/null || true
|
|
28
|
-
|
|
29
|
-
# Normalize to lowercase for matching
|
|
30
|
-
LOWER=$(echo "$PROMPT" | tr '[:upper:]' '[:lower:]')
|
|
31
|
-
|
|
32
|
-
if [ -f "$PROMPT_GUARD" ]; then
|
|
33
|
-
GUARD_RESULT=$(node "$PROMPT_GUARD" 2>/dev/null || true)
|
|
34
|
-
if [ -n "$GUARD_RESULT" ]; then
|
|
35
|
-
echo "$GUARD_RESULT"
|
|
36
|
-
exit 0
|
|
37
|
-
fi
|
|
38
|
-
fi
|
|
39
|
-
|
|
40
|
-
capture_and_report() {
|
|
41
|
-
local SIGNAL="$1"
|
|
42
|
-
|
|
43
|
-
# Capture feedback (verbose output already shows IDs, signal, storage)
|
|
44
|
-
node "$CAPTURE" --feedback="$SIGNAL" --context="$PROMPT" --tags="auto-capture,hook"
|
|
45
|
-
local CAPTURE_STATUS=$?
|
|
46
|
-
|
|
47
|
-
if [ "$CAPTURE_STATUS" -eq 2 ]; then
|
|
48
|
-
echo "Reusable memory status: signal logged only. Add one specific sentence so the MCP can promote it."
|
|
49
|
-
echo ""
|
|
50
|
-
fi
|
|
51
|
-
|
|
52
|
-
# Show storage proof
|
|
53
|
-
echo ""
|
|
54
|
-
echo "Storage Proof:"
|
|
55
|
-
echo " Feedback log : $FEEDBACK_LOG ($(wc -l < "$FEEDBACK_LOG" 2>/dev/null || echo 0) entries)"
|
|
56
|
-
echo " Memory log : $MEMORY_LOG ($(wc -l < "$MEMORY_LOG" 2>/dev/null || echo 0) entries)"
|
|
57
|
-
echo " LanceDB : $FEEDBACK_DIR/lancedb/"
|
|
58
|
-
echo ""
|
|
59
|
-
|
|
60
|
-
# Show last entry written
|
|
61
|
-
echo "Last Entry Written:"
|
|
62
|
-
tail -1 "$FEEDBACK_LOG" 2>/dev/null | node -e "
|
|
63
|
-
const d = JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));
|
|
64
|
-
console.log(' ID :', d.id);
|
|
65
|
-
console.log(' Signal :', d.signal, '(' + d.actionType + ')');
|
|
66
|
-
console.log(' Context :', (d.context||'').slice(0,80));
|
|
67
|
-
console.log(' Tags :', (d.tags||[]).join(', '));
|
|
68
|
-
console.log(' Timestamp :', d.timestamp);
|
|
69
|
-
console.log(' Domain :', (d.richContext||{}).domain || 'general');
|
|
70
|
-
" 2>/dev/null
|
|
71
|
-
|
|
72
|
-
# Show cumulative stats
|
|
73
|
-
echo ""
|
|
74
|
-
echo "Cumulative Stats:"
|
|
75
|
-
node -e "
|
|
76
|
-
const fs = require('fs');
|
|
77
|
-
const lines = fs.readFileSync('$FEEDBACK_LOG','utf8').trim().split('\n').filter(Boolean);
|
|
78
|
-
const entries = lines.map(l => { try { return JSON.parse(l); } catch(e) { return null; } }).filter(Boolean);
|
|
79
|
-
const pos = entries.filter(e => e.signal === 'positive').length;
|
|
80
|
-
const neg = entries.filter(e => e.signal === 'negative').length;
|
|
81
|
-
const promoted = entries.filter(e => e.actionType === 'store-learning' || e.actionType === 'store-mistake').length;
|
|
82
|
-
console.log(' Total feedback :', entries.length);
|
|
83
|
-
console.log(' Positive (up) :', pos);
|
|
84
|
-
console.log(' Negative (down) :', neg);
|
|
85
|
-
console.log(' Promoted to mem :', promoted);
|
|
86
|
-
console.log(' Ratio :', pos > 0 ? (pos/(pos+neg)*100).toFixed(0) + '% positive' : 'n/a');
|
|
87
|
-
" 2>/dev/null
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
# Check for thumbs up signals
|
|
91
|
-
if echo "$LOWER" | grep -qE '(thumbs? ?up|that worked|looks good|nice work|perfect|good job)'; then
|
|
92
|
-
capture_and_report "up"
|
|
93
|
-
exit 0
|
|
94
|
-
fi
|
|
95
|
-
|
|
96
|
-
# Check for thumbs down signals
|
|
97
|
-
if echo "$LOWER" | grep -qE '(thumbs? ?down|that failed|that was wrong|fix this)'; then
|
|
98
|
-
capture_and_report "down"
|
|
99
|
-
exit 0
|
|
100
|
-
fi
|