thumbgate 1.7.0 → 1.9.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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/.well-known/llms.txt +4 -0
- package/.well-known/mcp/server-card.json +9 -226
- package/adapters/README.md +1 -1
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/mcp/server-stdio.js +95 -1
- package/adapters/opencode/opencode.json +1 -1
- package/config/mcp-allowlists.json +15 -1
- package/package.json +13 -6
- package/public/index.html +2 -2
- package/scripts/agent-readiness.js +1 -0
- package/scripts/autonomous-workflow.js +377 -0
- package/scripts/autoresearch-runner.js +228 -0
- package/scripts/billing.js +4 -2
- package/scripts/mailer/resend-mailer.js +210 -40
- package/scripts/multimodal-retrieval-plan.js +110 -0
- package/scripts/statusline-context.js +207 -0
- package/scripts/statusline.sh +31 -14
- package/scripts/tool-registry.js +76 -0
- package/src/api/server.js +246 -0
- package/CHANGELOG.md +0 -702
package/scripts/statusline.sh
CHANGED
|
@@ -108,17 +108,28 @@ fi
|
|
|
108
108
|
# ── ThumbGate package metadata ────────────────────────────────────────
|
|
109
109
|
TG_VERSION="unknown"; TG_TIER="Free"
|
|
110
110
|
_META_JSON=$(node "${SCRIPT_DIR}/statusline-meta.js" 2>/dev/null)
|
|
111
|
-
if [ -n "$_META_JSON" ]; then
|
|
111
|
+
if [[ -n "$_META_JSON" ]]; then
|
|
112
112
|
eval "$(echo "$_META_JSON" | jq -r '
|
|
113
113
|
@sh "TG_VERSION=\(.version // "unknown")",
|
|
114
114
|
@sh "TG_TIER=\(.tier // "Free")"
|
|
115
115
|
' 2>/dev/null)"
|
|
116
116
|
fi
|
|
117
117
|
|
|
118
|
+
# ── Repo context (branch / work item / PR) ───────────────────────────
|
|
119
|
+
BRANCH_NAME=""; WORK_ITEM_LABEL=""; PR_LABEL=""
|
|
120
|
+
_CONTEXT_JSON=$(node "${SCRIPT_DIR}/statusline-context.js" 2>/dev/null)
|
|
121
|
+
if [[ -n "$_CONTEXT_JSON" ]]; then
|
|
122
|
+
eval "$(echo "$_CONTEXT_JSON" | jq -r '
|
|
123
|
+
@sh "BRANCH_NAME=\(.branchName // "")",
|
|
124
|
+
@sh "WORK_ITEM_LABEL=\(.workItemLabel // "")",
|
|
125
|
+
@sh "PR_LABEL=\(.prLabel // "")"
|
|
126
|
+
' 2>/dev/null)"
|
|
127
|
+
fi
|
|
128
|
+
|
|
118
129
|
# ── Control Tower stats ──────────────────────────────────────────
|
|
119
130
|
SLO_V="0"; AT_RISK="0"; ANOMALIES="0"
|
|
120
131
|
_TOWER_JSON=$(node "${SCRIPT_DIR}/statusline-tower.js" 2>/dev/null)
|
|
121
|
-
if [ -n "$_TOWER_JSON" ]; then
|
|
132
|
+
if [[ -n "$_TOWER_JSON" ]]; then
|
|
122
133
|
eval "$(echo "$_TOWER_JSON" | jq -r '
|
|
123
134
|
@sh "SLO_V=\(.sloViolations // 0)",
|
|
124
135
|
@sh "AT_RISK=\(.atRiskToolCount // 0)",
|
|
@@ -129,7 +140,7 @@ fi
|
|
|
129
140
|
# ── Latest lesson (data available for extensions; not rendered in statusbar) ──
|
|
130
141
|
LESSON_TEXT=""; LESSON_ID=""; LESSON_LABEL=""; LESSON_LINK=""
|
|
131
142
|
_LESSON_JSON=$(node "${SCRIPT_DIR}/statusline-lesson.js" 2>/dev/null)
|
|
132
|
-
if [ -n "$_LESSON_JSON" ]; then
|
|
143
|
+
if [[ -n "$_LESSON_JSON" ]]; then
|
|
133
144
|
eval "$(echo "$_LESSON_JSON" | jq -r '
|
|
134
145
|
@sh "LESSON_TEXT=\(.text // "")",
|
|
135
146
|
@sh "LESSON_ID=\(.lessonId // "")",
|
|
@@ -155,7 +166,7 @@ osc_link() {
|
|
|
155
166
|
# ThumbGate as a non-last row in a multi-line statusline should set this, because
|
|
156
167
|
# some agents (Claude Code) silently drop downstream rows when a preceding row
|
|
157
168
|
# contains OSC 8 sequences.
|
|
158
|
-
if [ "${THUMBGATE_STATUSLINE_PLAIN:-0}" = "1" ]; then
|
|
169
|
+
if [[ "${THUMBGATE_STATUSLINE_PLAIN:-0}" = "1" ]]; then
|
|
159
170
|
printf '%s' "$label"
|
|
160
171
|
return 0
|
|
161
172
|
fi
|
|
@@ -171,9 +182,9 @@ DOWN_LINK="$(osc_link "$DOWN_URL" "👎")"
|
|
|
171
182
|
DASHBOARD_LINK="$(osc_link "$DASHBOARD_URL" "$DASHBOARD_LABEL")"
|
|
172
183
|
LESSONS_LINK="$(osc_link "$LESSONS_URL" "$LESSONS_LABEL")"
|
|
173
184
|
LATEST_LESSON_LINK=""
|
|
174
|
-
if [ -n "$LESSON_LABEL" ]; then
|
|
185
|
+
if [[ -n "$LESSON_LABEL" ]]; then
|
|
175
186
|
_DISPLAY_LINK="$LESSON_LINK"
|
|
176
|
-
if [ -n "$LESSON_TEXT" ]; then
|
|
187
|
+
if [[ -n "$LESSON_TEXT" ]]; then
|
|
177
188
|
LATEST_LESSON_LINK="$(osc_link "$_DISPLAY_LINK" "${LESSON_LABEL}: ${LESSON_TEXT}")"
|
|
178
189
|
else
|
|
179
190
|
LATEST_LESSON_LINK="$(osc_link "$_DISPLAY_LINK" "$LESSON_LABEL")"
|
|
@@ -181,20 +192,26 @@ if [ -n "$LESSON_LABEL" ]; then
|
|
|
181
192
|
fi
|
|
182
193
|
|
|
183
194
|
# ── Output (single line) ─────────────────────────────────────────
|
|
184
|
-
LINE="
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
195
|
+
LINE=""
|
|
196
|
+
[[ -n "$BRANCH_NAME" ]] && LINE="${BRANCH_NAME}"
|
|
197
|
+
[[ -n "$WORK_ITEM_LABEL" ]] && LINE="${LINE:+${LINE} · }${WORK_ITEM_LABEL}"
|
|
198
|
+
LINE="${LINE:+${LINE} · }ThumbGate v${TG_VERSION} · ${TG_TIER}"
|
|
199
|
+
if [[ "$UP" = "0" && "$DOWN" = "0" ]]; then
|
|
200
|
+
LINE="${D}${LINE}${RST} · no feedback yet"
|
|
201
|
+
[[ -n "$PR_LABEL" ]] && LINE="${LINE} · ${D}${PR_LABEL}${RST}"
|
|
202
|
+
LINE="${LINE} · ${C}${DASHBOARD_LINK}${RST} · ${M}${LESSONS_LINK}${RST}"
|
|
203
|
+
[[ -n "$LATEST_LESSON_LINK" ]] && LINE="${LINE} · ${D}${LATEST_LESSON_LINK}${RST}"
|
|
188
204
|
printf '%b\n' "$LINE"
|
|
189
205
|
else
|
|
190
206
|
LINE="${LINE} · ${G}${BD}${UP}${RST}${UP_LINK} ${R}${BD}${DOWN}${RST}${DOWN_LINK} ${ARROW}"
|
|
191
207
|
|
|
192
208
|
# Control Tower alerts (if any)
|
|
193
|
-
[ "${SLO_V:-0}" -gt 0 ] && LINE="${LINE} ${R}${SLO_V} SLO${RST}"
|
|
194
|
-
[ "${AT_RISK:-0}" -gt 0 ] && LINE="${LINE} ${R}${AT_RISK}⚠${RST}"
|
|
195
|
-
[ "${ANOMALIES:-0}" -gt 0 ] && LINE="${LINE} ${R}${ANOMALIES}☠${RST}"
|
|
209
|
+
[[ "${SLO_V:-0}" -gt 0 ]] && LINE="${LINE} ${R}${SLO_V} SLO${RST}"
|
|
210
|
+
[[ "${AT_RISK:-0}" -gt 0 ]] && LINE="${LINE} ${R}${AT_RISK}⚠${RST}"
|
|
211
|
+
[[ "${ANOMALIES:-0}" -gt 0 ]] && LINE="${LINE} ${R}${ANOMALIES}☠${RST}"
|
|
212
|
+
[[ -n "$PR_LABEL" ]] && LINE="${LINE} · ${D}${PR_LABEL}${RST}"
|
|
196
213
|
LINE="${LINE} · ${C}${DASHBOARD_LINK}${RST} · ${M}${LESSONS_LINK}${RST}"
|
|
197
|
-
[ -n "$LATEST_LESSON_LINK" ] && LINE="${LINE} · ${D}${LATEST_LESSON_LINK}${RST}"
|
|
214
|
+
[[ -n "$LATEST_LESSON_LINK" ]] && LINE="${LINE} · ${D}${LATEST_LESSON_LINK}${RST}"
|
|
198
215
|
|
|
199
216
|
printf '%b\n' "$LINE"
|
|
200
217
|
fi
|
package/scripts/tool-registry.js
CHANGED
|
@@ -134,6 +134,25 @@ const TOOLS = [
|
|
|
134
134
|
},
|
|
135
135
|
},
|
|
136
136
|
}),
|
|
137
|
+
readOnlyTool({
|
|
138
|
+
name: 'plan_multimodal_retrieval',
|
|
139
|
+
description: 'Plan a high-ROI multimodal retrieval rollout for screenshots, PDF pages, dashboard captures, and proof artifacts without starting GPU training.',
|
|
140
|
+
inputSchema: {
|
|
141
|
+
type: 'object',
|
|
142
|
+
properties: {
|
|
143
|
+
goal: { type: 'string', description: 'Business or workflow objective for visual/document retrieval.' },
|
|
144
|
+
evidenceTypes: {
|
|
145
|
+
type: 'array',
|
|
146
|
+
items: { type: 'string' },
|
|
147
|
+
description: 'Evidence surfaces to include, such as screenshots, pdf_pages, proof_artifacts, dashboards, or videos.',
|
|
148
|
+
},
|
|
149
|
+
corpusItems: { type: 'number', description: 'Estimated number of visual artifacts or document pages to index.' },
|
|
150
|
+
maxEmbeddingDim: { type: 'number', description: 'Maximum embedding dimension to budget for Matryoshka-style truncation planning.' },
|
|
151
|
+
latencyBudgetMs: { type: 'number', description: 'Target retrieval latency budget for agent recall.' },
|
|
152
|
+
useReranker: { type: 'boolean', description: 'Whether to include a multimodal reranker stage after initial embedding retrieval.' },
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
}),
|
|
137
156
|
destructiveTool({
|
|
138
157
|
name: 'import_document',
|
|
139
158
|
description: 'Import a local policy or runbook document into ThumbGate, normalize it for search, and propose provenance-backed gate candidates.',
|
|
@@ -872,6 +891,24 @@ const TOOLS = [
|
|
|
872
891
|
},
|
|
873
892
|
},
|
|
874
893
|
}),
|
|
894
|
+
destructiveTool({
|
|
895
|
+
name: 'run_autoresearch',
|
|
896
|
+
description: 'Run a bounded metric-improvement loop: measure a baseline, test a hypothesis, require primary and holdout checks, then keep or discard the candidate mutation with proof.',
|
|
897
|
+
inputSchema: {
|
|
898
|
+
type: 'object',
|
|
899
|
+
properties: {
|
|
900
|
+
iterations: { type: 'number', description: 'Number of iterations to run. Capped at 5 per call; default 1.' },
|
|
901
|
+
targetName: { type: 'string', enum: ['half_life_days', 'decay_floor', 'prevention_min_occurrences', 'verification_max_retries', 'dpo_beta'], description: 'Optional evolution target to mutate.' },
|
|
902
|
+
nextValue: { type: 'number', description: 'Optional explicit candidate value for the target.' },
|
|
903
|
+
testCommand: { type: 'string', description: 'Primary metric command. Defaults to npm test.' },
|
|
904
|
+
holdoutCommands: { type: 'array', items: { type: 'string' }, description: 'Additional checks required before a candidate can be kept.' },
|
|
905
|
+
timeoutMs: { type: 'number', description: 'Per-command timeout in milliseconds. Capped at 600000; default 120000.' },
|
|
906
|
+
cwd: { type: 'string', description: 'Optional workspace directory for the evaluation commands.' },
|
|
907
|
+
researchQuery: { type: 'string', description: 'Optional research query used to build an autoresearch context brief.' },
|
|
908
|
+
paperLimit: { type: 'number', description: 'Maximum research papers to ingest when researchQuery is set. Capped at 10; default 5.' },
|
|
909
|
+
},
|
|
910
|
+
},
|
|
911
|
+
}),
|
|
875
912
|
destructiveTool({
|
|
876
913
|
name: 'schedule',
|
|
877
914
|
description: 'Create, list, or delete scheduled tasks. Supports natural language scheduling like "daily 9:00", "weekly monday 8:30", "hourly". Installs as macOS LaunchAgent or Linux crontab.',
|
|
@@ -1041,6 +1078,45 @@ const TOOLS = [
|
|
|
1041
1078
|
properties: {},
|
|
1042
1079
|
},
|
|
1043
1080
|
}),
|
|
1081
|
+
readOnlyTool({
|
|
1082
|
+
name: 'require_evidence_for_claim',
|
|
1083
|
+
description: 'Leader-Agent completion gate. Before any agent declares done/fixed/shipped/resolved, require tracked evidence. Blocking response when evidence missing; callers honor the blocking flag to stop completion claims.',
|
|
1084
|
+
inputSchema: {
|
|
1085
|
+
type: 'object',
|
|
1086
|
+
required: ['claim'],
|
|
1087
|
+
properties: {
|
|
1088
|
+
claim: { type: 'string', description: 'The completion claim text to verify (e.g. "Fix shipped", "Tests passing")' },
|
|
1089
|
+
mode: { type: 'string', enum: ['blocking', 'advisory'], description: 'blocking (default) returns blocking=true when evidence missing; advisory returns blocking=false' },
|
|
1090
|
+
sessionId: { type: 'string', description: 'Optional session id to associate with the gate decision' },
|
|
1091
|
+
},
|
|
1092
|
+
},
|
|
1093
|
+
}),
|
|
1094
|
+
destructiveTool({
|
|
1095
|
+
name: 'distribute_context_to_agents',
|
|
1096
|
+
description: 'Leader-Agent swarm coordinator. Constructs one context pack and distributes it to N worker agents (perplexity-bug-resolver, codex-reviewer, grok-x-intelligence, etc.), recording provenance per agent. Replaces N independent context derivations with a single shared pack.',
|
|
1097
|
+
inputSchema: {
|
|
1098
|
+
type: 'object',
|
|
1099
|
+
required: ['agents'],
|
|
1100
|
+
properties: {
|
|
1101
|
+
query: { type: 'string', description: 'Context query used to construct the pack' },
|
|
1102
|
+
agents: { type: 'array', items: { type: 'string' }, description: 'Agent names that should receive the pack' },
|
|
1103
|
+
maxItems: { type: 'number', description: 'Max items in the constructed pack (default 8)' },
|
|
1104
|
+
maxChars: { type: 'number', description: 'Max characters in the constructed pack (default 6000)' },
|
|
1105
|
+
namespaces: { type: 'array', items: { type: 'string' }, description: 'Optional contextfs namespaces to source from' },
|
|
1106
|
+
ttlMs: { type: 'number', description: 'Optional pack TTL in milliseconds (default 15 minutes)' },
|
|
1107
|
+
},
|
|
1108
|
+
},
|
|
1109
|
+
}),
|
|
1110
|
+
readOnlyTool({
|
|
1111
|
+
name: 'session_report',
|
|
1112
|
+
description: 'Unified observability rollup. Aggregates feedback stats, gate stats, and recent context/provenance events over a time window in one call. Replaces separate dashboard/gate_stats/feedback_stats calls with a single LangSmith-style report.',
|
|
1113
|
+
inputSchema: {
|
|
1114
|
+
type: 'object',
|
|
1115
|
+
properties: {
|
|
1116
|
+
windowHours: { type: 'number', description: 'Lookback window in hours (default 24, max 720)' },
|
|
1117
|
+
},
|
|
1118
|
+
},
|
|
1119
|
+
}),
|
|
1044
1120
|
readOnlyTool({
|
|
1045
1121
|
name: 'context_stuff_lessons',
|
|
1046
1122
|
description: 'Dump ALL prevention lessons into a single text block for context-window injection. Bypasses RAG/search — returns every lesson sorted by confidence. For most projects (20-200 lessons), fits in 1K-10K tokens.',
|
package/src/api/server.js
CHANGED
|
@@ -552,6 +552,169 @@ function getServerCardTools() {
|
|
|
552
552
|
}));
|
|
553
553
|
}
|
|
554
554
|
|
|
555
|
+
function buildPublicUrl(hostedConfig, pathname) {
|
|
556
|
+
return `${hostedConfig.appOrigin}${pathname}`;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
const VERIFICATION_EVIDENCE_URL = 'https://github.com/IgorGanapolsky/ThumbGate/blob/main/docs/VERIFICATION_EVIDENCE.md';
|
|
560
|
+
|
|
561
|
+
function getToolDiscoveryIndex(hostedConfig) {
|
|
562
|
+
return MCP_TOOLS.map((tool) => ({
|
|
563
|
+
name: tool.name,
|
|
564
|
+
description: tool.description,
|
|
565
|
+
annotations: tool.annotations || {},
|
|
566
|
+
schemaUrl: buildPublicUrl(hostedConfig, `/.well-known/mcp/tools/${encodeURIComponent(tool.name)}.json`),
|
|
567
|
+
}));
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
function getMcpSkillManifests(hostedConfig) {
|
|
571
|
+
return [
|
|
572
|
+
{
|
|
573
|
+
name: 'thumbgate',
|
|
574
|
+
title: 'ThumbGate Pre-Action Gates',
|
|
575
|
+
description: 'Capture feedback, recall lessons, generate rules, and block repeated agent mistakes before tool execution.',
|
|
576
|
+
triggers: ['thumbgate', 'pre-action gates', 'prevent repeated AI mistakes', 'agent feedback', 'PreToolUse hooks'],
|
|
577
|
+
recommendedFlow: [
|
|
578
|
+
'Recall lessons before risky work.',
|
|
579
|
+
'Plan high-risk actions with checkpoints.',
|
|
580
|
+
'Capture concrete thumbs-down/up feedback.',
|
|
581
|
+
'Inspect prevention_rules after repeats.',
|
|
582
|
+
],
|
|
583
|
+
installCommand: 'npx thumbgate init',
|
|
584
|
+
contextUrl: buildPublicUrl(hostedConfig, '/public/llm-context.md'),
|
|
585
|
+
proofUrl: VERIFICATION_EVIDENCE_URL,
|
|
586
|
+
},
|
|
587
|
+
{
|
|
588
|
+
name: 'workflow-hardening-sprint',
|
|
589
|
+
title: 'Workflow Hardening Sprint',
|
|
590
|
+
description: 'Turn one repeated agent failure into an enforced gate with proof and rollout evidence.',
|
|
591
|
+
triggers: ['workflow hardening', 'team rollout', 'agent governance', 'approval boundary', 'audit trail'],
|
|
592
|
+
recommendedFlow: [
|
|
593
|
+
'Pick one costly repeated failure.',
|
|
594
|
+
'Import the policy or runbook.',
|
|
595
|
+
'Ship the gate with dashboard proof.',
|
|
596
|
+
],
|
|
597
|
+
intakeUrl: buildPublicUrl(hostedConfig, '/#workflow-sprint-intake'),
|
|
598
|
+
proofUrl: VERIFICATION_EVIDENCE_URL,
|
|
599
|
+
},
|
|
600
|
+
{
|
|
601
|
+
name: 'visual-proof-retrieval',
|
|
602
|
+
title: 'Visual Proof Retrieval',
|
|
603
|
+
description: 'Use screenshots, PDF pages, dashboard captures, and proof artifacts as searchable evidence for agent-governance claims.',
|
|
604
|
+
triggers: ['visual document retrieval', 'multimodal embeddings', 'screenshots', 'PDF evidence', 'proof artifacts'],
|
|
605
|
+
recommendedFlow: [
|
|
606
|
+
'Plan the corpus and Matryoshka dimension budget.',
|
|
607
|
+
'Baseline text-only retrieval before finetuning.',
|
|
608
|
+
'Evaluate NDCG@10 on visual hard negatives.',
|
|
609
|
+
'Require artifact links before using retrieved evidence in claims.',
|
|
610
|
+
],
|
|
611
|
+
contextUrl: buildPublicUrl(hostedConfig, '/public/llm-context.md'),
|
|
612
|
+
proofUrl: VERIFICATION_EVIDENCE_URL,
|
|
613
|
+
},
|
|
614
|
+
];
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
function getMcpApplications(hostedConfig) {
|
|
618
|
+
return [
|
|
619
|
+
{
|
|
620
|
+
name: 'dashboard',
|
|
621
|
+
title: 'ThumbGate Dashboard',
|
|
622
|
+
description: 'Review feedback, gates, blocked actions, funnel metrics, and proof.',
|
|
623
|
+
url: buildPublicUrl(hostedConfig, '/dashboard'),
|
|
624
|
+
useWhen: 'Need proof before approving more autonomy.',
|
|
625
|
+
},
|
|
626
|
+
{
|
|
627
|
+
name: 'lessons',
|
|
628
|
+
title: 'Lessons',
|
|
629
|
+
description: 'Browse promoted lessons and corrective actions.',
|
|
630
|
+
url: buildPublicUrl(hostedConfig, '/lessons'),
|
|
631
|
+
useWhen: 'Need human-approved context before risk.',
|
|
632
|
+
},
|
|
633
|
+
{
|
|
634
|
+
name: 'guide',
|
|
635
|
+
title: 'Setup Guide',
|
|
636
|
+
description: 'Install ThumbGate for Claude Code, Cursor, Codex, Gemini CLI, Amp, OpenCode, and MCP agents.',
|
|
637
|
+
url: buildPublicUrl(hostedConfig, '/guide'),
|
|
638
|
+
useWhen: 'Need setup without searching the repo.',
|
|
639
|
+
},
|
|
640
|
+
{
|
|
641
|
+
name: 'workflow-sprint-intake',
|
|
642
|
+
title: 'Workflow Hardening Sprint Intake',
|
|
643
|
+
description: 'Submit a repeated agent failure for a proof-backed sprint.',
|
|
644
|
+
url: buildPublicUrl(hostedConfig, '/#workflow-sprint-intake'),
|
|
645
|
+
useWhen: 'Ready to convert mistakes into gates.',
|
|
646
|
+
},
|
|
647
|
+
];
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
function getMcpDiscoveryManifest(hostedConfig) {
|
|
651
|
+
return {
|
|
652
|
+
schemaVersion: '2026-04-20',
|
|
653
|
+
name: 'thumbgate',
|
|
654
|
+
title: 'ThumbGate',
|
|
655
|
+
version: pkg.version,
|
|
656
|
+
description: 'Pre-Action Gates for AI coding agents: feedback, recall, prevention rules, and tool-call blocking.',
|
|
657
|
+
homepage: hostedConfig.appOrigin,
|
|
658
|
+
repository: 'https://github.com/IgorGanapolsky/ThumbGate',
|
|
659
|
+
package: {
|
|
660
|
+
registry: 'npm',
|
|
661
|
+
name: 'thumbgate',
|
|
662
|
+
installCommand: 'npx thumbgate init',
|
|
663
|
+
},
|
|
664
|
+
transport: {
|
|
665
|
+
type: 'streamable-http',
|
|
666
|
+
endpoint: buildPublicUrl(hostedConfig, '/mcp'),
|
|
667
|
+
unauthenticatedDiscovery: ['initialize', 'tools/list'],
|
|
668
|
+
authenticatedMethods: ['tools/call'],
|
|
669
|
+
},
|
|
670
|
+
discovery: {
|
|
671
|
+
serverCardUrl: buildPublicUrl(hostedConfig, '/.well-known/mcp/server-card.json'),
|
|
672
|
+
toolIndexUrl: buildPublicUrl(hostedConfig, '/.well-known/mcp/tools.json'),
|
|
673
|
+
toolSchemaUrlTemplate: buildPublicUrl(hostedConfig, '/.well-known/mcp/tools/{name}.json'),
|
|
674
|
+
skillsUrl: buildPublicUrl(hostedConfig, '/.well-known/mcp/skills.json'),
|
|
675
|
+
applicationsUrl: buildPublicUrl(hostedConfig, '/.well-known/mcp/applications.json'),
|
|
676
|
+
llmsTxtUrl: buildPublicUrl(hostedConfig, '/.well-known/llms.txt'),
|
|
677
|
+
progressive: {
|
|
678
|
+
pattern: 'Load manifest, inspect tools.json, fetch one tool schema only when needed.',
|
|
679
|
+
tokenStrategy: 'Do not preload every inputSchema. Use per-tool schema URLs.',
|
|
680
|
+
},
|
|
681
|
+
},
|
|
682
|
+
primaryFlows: [
|
|
683
|
+
{
|
|
684
|
+
name: 'capture-to-gate',
|
|
685
|
+
description: 'Capture feedback, retrieve lessons, generate rules, enforce a gate.',
|
|
686
|
+
tools: ['capture_feedback', 'search_lessons', 'prevention_rules', 'gate_stats'],
|
|
687
|
+
},
|
|
688
|
+
{
|
|
689
|
+
name: 'safe-autonomous-work',
|
|
690
|
+
description: 'Plan high-risk work, recall lessons, diagnose failures.',
|
|
691
|
+
tools: ['plan_intent', 'recall', 'diagnose_failure', 'feedback_summary'],
|
|
692
|
+
},
|
|
693
|
+
{
|
|
694
|
+
name: 'team-rollout-proof',
|
|
695
|
+
description: 'Show dashboard evidence, metrics, and sprint proof.',
|
|
696
|
+
tools: ['dashboard', 'get_business_metrics', 'construct_context_pack'],
|
|
697
|
+
},
|
|
698
|
+
{
|
|
699
|
+
name: 'metric-autoresearch',
|
|
700
|
+
description: 'Run bounded baseline -> hypothesis -> holdout loops with keep/discard proof.',
|
|
701
|
+
tools: ['get_business_metrics', 'construct_context_pack', 'run_autoresearch', 'require_evidence_for_claim'],
|
|
702
|
+
},
|
|
703
|
+
{
|
|
704
|
+
name: 'visual-proof-retrieval',
|
|
705
|
+
description: 'Plan screenshot/PDF/proof-artifact retrieval before investing in multimodal finetuning.',
|
|
706
|
+
tools: ['plan_multimodal_retrieval', 'search_thumbgate', 'construct_context_pack', 'require_evidence_for_claim'],
|
|
707
|
+
},
|
|
708
|
+
],
|
|
709
|
+
skills: getMcpSkillManifests(hostedConfig),
|
|
710
|
+
applications: getMcpApplications(hostedConfig),
|
|
711
|
+
proof: {
|
|
712
|
+
verificationEvidenceUrl: VERIFICATION_EVIDENCE_URL,
|
|
713
|
+
llmContextUrl: buildPublicUrl(hostedConfig, '/public/llm-context.md'),
|
|
714
|
+
},
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
|
|
555
718
|
function createHttpError(statusCode, message) {
|
|
556
719
|
const err = new Error(message);
|
|
557
720
|
err.statusCode = statusCode;
|
|
@@ -3904,7 +4067,85 @@ async function addContext(){
|
|
|
3904
4067
|
return;
|
|
3905
4068
|
}
|
|
3906
4069
|
|
|
4070
|
+
if (isGetLikeRequest && pathname === '/.well-known/mcp.json') {
|
|
4071
|
+
sendJson(res, 200, getMcpDiscoveryManifest(hostedConfig), {}, {
|
|
4072
|
+
headOnly: isHeadRequest,
|
|
4073
|
+
});
|
|
4074
|
+
return;
|
|
4075
|
+
}
|
|
4076
|
+
|
|
4077
|
+
if (isGetLikeRequest && pathname === '/.well-known/mcp/tools.json') {
|
|
4078
|
+
sendJson(res, 200, {
|
|
4079
|
+
name: 'thumbgate',
|
|
4080
|
+
version: pkg.version,
|
|
4081
|
+
count: MCP_TOOLS.length,
|
|
4082
|
+
tools: getToolDiscoveryIndex(hostedConfig),
|
|
4083
|
+
}, {}, {
|
|
4084
|
+
headOnly: isHeadRequest,
|
|
4085
|
+
});
|
|
4086
|
+
return;
|
|
4087
|
+
}
|
|
4088
|
+
|
|
4089
|
+
if (isGetLikeRequest && pathname.startsWith('/.well-known/mcp/tools/') && pathname.endsWith('.json')) {
|
|
4090
|
+
const encodedToolName = pathname.slice('/.well-known/mcp/tools/'.length, -'.json'.length);
|
|
4091
|
+
let toolName = encodedToolName;
|
|
4092
|
+
try {
|
|
4093
|
+
toolName = decodeURIComponent(encodedToolName);
|
|
4094
|
+
} catch (_err) {
|
|
4095
|
+
sendJson(res, 400, {
|
|
4096
|
+
error: 'invalid_tool_name',
|
|
4097
|
+
toolIndexUrl: buildPublicUrl(hostedConfig, '/.well-known/mcp/tools.json'),
|
|
4098
|
+
}, {}, {
|
|
4099
|
+
headOnly: isHeadRequest,
|
|
4100
|
+
});
|
|
4101
|
+
return;
|
|
4102
|
+
}
|
|
4103
|
+
const tool = MCP_TOOLS.find((candidate) => candidate.name === toolName);
|
|
4104
|
+
if (!tool) {
|
|
4105
|
+
sendJson(res, 404, {
|
|
4106
|
+
error: 'tool_not_found',
|
|
4107
|
+
toolName,
|
|
4108
|
+
toolIndexUrl: buildPublicUrl(hostedConfig, '/.well-known/mcp/tools.json'),
|
|
4109
|
+
}, {}, {
|
|
4110
|
+
headOnly: isHeadRequest,
|
|
4111
|
+
});
|
|
4112
|
+
return;
|
|
4113
|
+
}
|
|
4114
|
+
sendJson(res, 200, {
|
|
4115
|
+
name: tool.name,
|
|
4116
|
+
description: tool.description,
|
|
4117
|
+
annotations: tool.annotations || {},
|
|
4118
|
+
inputSchema: tool.inputSchema,
|
|
4119
|
+
}, {}, {
|
|
4120
|
+
headOnly: isHeadRequest,
|
|
4121
|
+
});
|
|
4122
|
+
return;
|
|
4123
|
+
}
|
|
4124
|
+
|
|
4125
|
+
if (isGetLikeRequest && pathname === '/.well-known/mcp/skills.json') {
|
|
4126
|
+
sendJson(res, 200, {
|
|
4127
|
+
name: 'thumbgate',
|
|
4128
|
+
version: pkg.version,
|
|
4129
|
+
skills: getMcpSkillManifests(hostedConfig),
|
|
4130
|
+
}, {}, {
|
|
4131
|
+
headOnly: isHeadRequest,
|
|
4132
|
+
});
|
|
4133
|
+
return;
|
|
4134
|
+
}
|
|
4135
|
+
|
|
4136
|
+
if (isGetLikeRequest && pathname === '/.well-known/mcp/applications.json') {
|
|
4137
|
+
sendJson(res, 200, {
|
|
4138
|
+
name: 'thumbgate',
|
|
4139
|
+
version: pkg.version,
|
|
4140
|
+
applications: getMcpApplications(hostedConfig),
|
|
4141
|
+
}, {}, {
|
|
4142
|
+
headOnly: isHeadRequest,
|
|
4143
|
+
});
|
|
4144
|
+
return;
|
|
4145
|
+
}
|
|
4146
|
+
|
|
3907
4147
|
if (isGetLikeRequest && pathname === '/.well-known/mcp/server-card.json') {
|
|
4148
|
+
const discoveryManifest = getMcpDiscoveryManifest(hostedConfig);
|
|
3908
4149
|
sendJson(res, 200, {
|
|
3909
4150
|
serverInfo: {
|
|
3910
4151
|
name: 'thumbgate',
|
|
@@ -3913,7 +4154,12 @@ async function addContext(){
|
|
|
3913
4154
|
name: 'thumbgate',
|
|
3914
4155
|
description: 'Pre-action gates that physically block AI coding agents from repeating known mistakes. Captures feedback, auto-promotes failures into prevention rules, and enforces them via PreToolUse hooks. Works with Claude Code, Codex, Gemini, Amp, Cursor, OpenCode, and any MCP-compatible agent.',
|
|
3915
4156
|
version: pkg.version,
|
|
4157
|
+
transport: discoveryManifest.transport,
|
|
4158
|
+
discovery: discoveryManifest.discovery,
|
|
3916
4159
|
tools: getServerCardTools(),
|
|
4160
|
+
skills: getMcpSkillManifests(hostedConfig),
|
|
4161
|
+
applications: getMcpApplications(hostedConfig),
|
|
4162
|
+
proof: discoveryManifest.proof,
|
|
3917
4163
|
repository: 'https://github.com/IgorGanapolsky/ThumbGate',
|
|
3918
4164
|
homepage: hostedConfig.appOrigin,
|
|
3919
4165
|
}, {}, {
|