thumbgate 1.14.1 → 1.16.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 +6 -6
- package/.claude-plugin/plugin.json +3 -3
- package/.well-known/llms.txt +5 -5
- package/.well-known/mcp/server-card.json +1 -1
- package/README.md +60 -35
- package/adapters/chatgpt/openapi.yaml +118 -2
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/mcp/server-stdio.js +217 -84
- package/adapters/opencode/opencode.json +1 -1
- package/bench/prompt-eval-suite.json +5 -1
- package/bin/cli.js +211 -8
- package/config/enforcement.json +59 -7
- package/config/evals/agent-safety-eval.json +338 -22
- package/config/gates/default.json +33 -0
- package/config/gates/routine.json +43 -0
- package/config/github-about.json +3 -3
- package/config/mcp-allowlists.json +4 -0
- package/config/merge-quality-checks.json +2 -1
- package/config/model-candidates.json +131 -0
- package/openapi/openapi.yaml +118 -2
- package/package.json +70 -51
- package/public/blog.html +7 -7
- package/public/codex-plugin.html +13 -7
- package/public/compare.html +29 -23
- package/public/dashboard.html +105 -12
- package/public/guide.html +28 -28
- package/public/index.html +233 -97
- package/public/learn.html +87 -20
- package/public/lessons.html +26 -2
- package/public/numbers.html +271 -0
- package/public/pro.html +89 -19
- package/scripts/agent-audit-trace.js +55 -0
- package/scripts/agent-memory-lifecycle.js +96 -0
- package/scripts/agent-readiness-plan.js +118 -0
- package/scripts/agentic-data-pipeline.js +21 -1
- package/scripts/agents-sdk-sandbox-plan.js +57 -0
- package/scripts/ai-org-governance.js +98 -0
- package/scripts/ai-search-distribution.js +43 -0
- package/scripts/artifact-agent-plan.js +81 -0
- package/scripts/billing.js +27 -8
- package/scripts/cli-feedback.js +2 -1
- package/scripts/cli-schema.js +60 -5
- package/scripts/code-mode-mcp-plan.js +71 -0
- package/scripts/commercial-offer.js +1 -1
- package/scripts/context-engine.js +1 -2
- package/scripts/context-manager.js +4 -1
- package/scripts/contextfs.js +214 -32
- package/scripts/dashboard-render-spec.js +1 -1
- package/scripts/dashboard.js +275 -9
- package/scripts/decision-journal.js +13 -3
- package/scripts/document-workflow-governance.js +62 -0
- package/scripts/enterprise-agent-rollout.js +34 -0
- package/scripts/experience-replay-governance.js +69 -0
- package/scripts/export-hf-dataset.js +1 -1
- package/scripts/feedback-loop.js +141 -9
- package/scripts/feedback-to-rules.js +17 -23
- package/scripts/gates-engine.js +4 -6
- package/scripts/growth-campaigns.js +49 -0
- package/scripts/harness-selector.js +145 -1
- package/scripts/hybrid-supervisor-agent.js +64 -0
- package/scripts/inference-cache-policy.js +72 -0
- package/scripts/inference-economics.js +53 -0
- package/scripts/internal-agent-bootstrap.js +12 -2
- package/scripts/knowledge-layer-plan.js +108 -0
- package/scripts/lesson-canonical.js +181 -0
- package/scripts/lesson-db.js +71 -10
- package/scripts/lesson-inference.js +183 -44
- package/scripts/lesson-search.js +4 -1
- package/scripts/lesson-synthesis.js +23 -2
- package/scripts/llm-client.js +157 -26
- package/scripts/mailer/resend-mailer.js +112 -1
- package/scripts/mcp-transport-strategy.js +66 -0
- package/scripts/memory-store-governance.js +60 -0
- package/scripts/meta-agent-loop.js +7 -13
- package/scripts/model-access-eligibility.js +38 -0
- package/scripts/model-migration-readiness.js +55 -0
- package/scripts/native-messaging-audit.js +514 -0
- package/scripts/operational-integrity.js +96 -3
- package/scripts/otel-declarative-config.js +56 -0
- package/scripts/perplexity-client.js +1 -1
- package/scripts/post-training-governance.js +34 -0
- package/scripts/pr-manager.js +47 -7
- package/scripts/private-core-boundary.js +72 -0
- package/scripts/production-agent-readiness.js +40 -0
- package/scripts/profile-router.js +16 -1
- package/scripts/prompt-eval.js +564 -32
- package/scripts/prompt-programs.js +93 -0
- package/scripts/provider-action-normalizer.js +585 -0
- package/scripts/rule-validator.js +285 -0
- package/scripts/scaling-law-claims.js +60 -0
- package/scripts/security-scanner.js +1 -1
- package/scripts/self-distill-agent.js +7 -32
- package/scripts/seo-gsd.js +400 -43
- package/scripts/skill-rag-router.js +53 -0
- package/scripts/spec-gate.js +1 -1
- package/scripts/student-consistent-training.js +73 -0
- package/scripts/synthetic-data-provenance.js +98 -0
- package/scripts/task-context-result.js +81 -0
- package/scripts/telemetry-analytics.js +149 -0
- package/scripts/thompson-sampling.js +2 -2
- package/scripts/token-savings.js +7 -6
- package/scripts/token-tco.js +46 -0
- package/scripts/tool-registry.js +75 -3
- package/scripts/verification-loop.js +10 -1
- package/scripts/verifier-scoring.js +71 -0
- package/scripts/workflow-sentinel.js +284 -28
- package/scripts/workspace-agent-routines.js +118 -0
- package/skills/thumbgate/SKILL.md +1 -1
- package/src/api/server.js +434 -120
- package/.claude-plugin/README.md +0 -170
- package/adapters/README.md +0 -12
- package/scripts/analytics-report.js +0 -328
- package/scripts/autonomous-workflow.js +0 -377
- package/scripts/billing-setup.js +0 -109
- package/scripts/creator-campaigns.js +0 -239
- package/scripts/cross-encoder-reranker.js +0 -235
- package/scripts/daemon-manager.js +0 -108
- package/scripts/decision-trace.js +0 -354
- package/scripts/delegation-runtime.js +0 -896
- package/scripts/dispatch-brief.js +0 -159
- package/scripts/distribution-surfaces.js +0 -110
- package/scripts/feedback-history-distiller.js +0 -382
- package/scripts/funnel-analytics.js +0 -35
- package/scripts/history-distiller.js +0 -200
- package/scripts/hosted-job-launcher.js +0 -256
- package/scripts/intent-router.js +0 -392
- package/scripts/lesson-reranker.js +0 -263
- package/scripts/lesson-retrieval.js +0 -148
- package/scripts/managed-lesson-agent.js +0 -183
- package/scripts/operational-dashboard.js +0 -103
- package/scripts/operational-summary.js +0 -129
- package/scripts/operator-artifacts.js +0 -608
- package/scripts/optimize-context.js +0 -17
- package/scripts/org-dashboard.js +0 -206
- package/scripts/partner-orchestration.js +0 -146
- package/scripts/predictive-insights.js +0 -356
- package/scripts/pulse.js +0 -80
- package/scripts/reflector-agent.js +0 -221
- package/scripts/sales-pipeline.js +0 -681
- package/scripts/session-episode-store.js +0 -329
- package/scripts/session-health-sensor.js +0 -242
- package/scripts/session-report.js +0 -120
- package/scripts/swarm-coordinator.js +0 -81
- package/scripts/tool-kpi-tracker.js +0 -12
- package/scripts/webhook-delivery.js +0 -62
- package/scripts/workflow-sprint-intake.js +0 -475
- package/skills/agent-memory/SKILL.md +0 -97
- package/skills/solve-architecture-autonomy/SKILL.md +0 -17
- package/skills/solve-architecture-autonomy/tool.js +0 -33
- package/skills/thumbgate-feedback/SKILL.md +0 -49
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
function normalizeText(value) {
|
|
5
|
+
if (value === undefined || value === null) return '';
|
|
6
|
+
return String(value).trim();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function normalizeBudget(value, fallback) {
|
|
10
|
+
const number = Number(value);
|
|
11
|
+
return Number.isFinite(number) && number >= 0 ? number : fallback;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function buildAiOrgGovernancePlan(input = {}) {
|
|
15
|
+
const mission = normalizeText(input.mission) || 'Continuously improve agent-governed workflows while staying within budget.';
|
|
16
|
+
const monthlyBudgetUsd = normalizeBudget(input.monthlyBudgetUsd, 25);
|
|
17
|
+
const roles = [
|
|
18
|
+
{
|
|
19
|
+
id: 'ceo',
|
|
20
|
+
title: 'Planner',
|
|
21
|
+
mission: 'Break goals into tickets, assign owners, and enforce ROI.',
|
|
22
|
+
monthlyBudgetUsd: normalizeBudget(input.ceoBudgetUsd, Math.min(10, monthlyBudgetUsd)),
|
|
23
|
+
canCreateAgents: false,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
id: 'research_analyst',
|
|
27
|
+
title: 'Research Analyst',
|
|
28
|
+
mission: 'Collect market and technical signals into structured briefs.',
|
|
29
|
+
monthlyBudgetUsd: normalizeBudget(input.researchBudgetUsd, Math.min(5, monthlyBudgetUsd)),
|
|
30
|
+
canCreateAgents: false,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: 'qa_operator',
|
|
34
|
+
title: 'QA Operator',
|
|
35
|
+
mission: 'Review evidence, tests, diffs, and spend anomalies before promotion.',
|
|
36
|
+
monthlyBudgetUsd: normalizeBudget(input.qaBudgetUsd, Math.min(5, monthlyBudgetUsd)),
|
|
37
|
+
canCreateAgents: false,
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
generatedAt: normalizeText(input.generatedAt) || new Date().toISOString(),
|
|
43
|
+
orgName: normalizeText(input.orgName) || 'ThumbGate Agent Company',
|
|
44
|
+
mission,
|
|
45
|
+
monthlyBudgetUsd,
|
|
46
|
+
roles,
|
|
47
|
+
ticketTemplates: [
|
|
48
|
+
{
|
|
49
|
+
id: 'market_signal_brief',
|
|
50
|
+
ownerRole: 'research_analyst',
|
|
51
|
+
outputSchema: ['source', 'claim', 'relevance', 'action', 'evidence'],
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: 'workflow_hardening',
|
|
55
|
+
ownerRole: 'ceo',
|
|
56
|
+
outputSchema: ['risk', 'gate', 'test', 'rollback', 'owner'],
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'evidence_review',
|
|
60
|
+
ownerRole: 'qa_operator',
|
|
61
|
+
outputSchema: ['claim', 'evidence', 'verdict', 'missing_proof'],
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
approvalGates: [
|
|
65
|
+
'new_agent_role',
|
|
66
|
+
'budget_increase',
|
|
67
|
+
'credentialed_connector_write',
|
|
68
|
+
'production_release',
|
|
69
|
+
'public_claim_without_evidence',
|
|
70
|
+
],
|
|
71
|
+
audit: {
|
|
72
|
+
daily: ['ticket outcomes', 'spend by role', 'blocked actions', 'open approvals'],
|
|
73
|
+
weekly: ['low ROI tickets', 'stale agents', 'budget cap changes', 'policy drift'],
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function evaluateAiOrgAction(action = {}, plan = buildAiOrgGovernancePlan()) {
|
|
79
|
+
const type = normalizeText(action.type);
|
|
80
|
+
const issues = [];
|
|
81
|
+
if (type === 'create_agent') issues.push('new_agent_role');
|
|
82
|
+
if (type === 'raise_budget') issues.push('budget_increase');
|
|
83
|
+
if (type === 'connector_write') issues.push('credentialed_connector_write');
|
|
84
|
+
if (type === 'public_claim' && !(Array.isArray(action.evidence) && action.evidence.length > 0)) {
|
|
85
|
+
issues.push('public_claim_without_evidence');
|
|
86
|
+
}
|
|
87
|
+
const gateHits = issues.filter((issue) => plan.approvalGates.includes(issue));
|
|
88
|
+
return {
|
|
89
|
+
decision: gateHits.length > 0 ? 'warn' : 'allow',
|
|
90
|
+
gateHits,
|
|
91
|
+
requiredApproval: gateHits.length > 0,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
module.exports = {
|
|
96
|
+
buildAiOrgGovernancePlan,
|
|
97
|
+
evaluateAiOrgAction,
|
|
98
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
function buildAiSearchDistributionPlan(input = {}) {
|
|
5
|
+
const brand = input.brand || 'ThumbGate';
|
|
6
|
+
const canonicalUrl = input.canonicalUrl || 'https://thumbgate-production.up.railway.app';
|
|
7
|
+
const proofUrl = input.proofUrl || `${canonicalUrl}/VERIFICATION_EVIDENCE.md`;
|
|
8
|
+
const claims = [
|
|
9
|
+
`${brand} is a pre-action gate system for AI agents.`,
|
|
10
|
+
`${brand} turns thumbs-up/down feedback into enforceable prevention rules.`,
|
|
11
|
+
`${brand} blocks known-bad tool actions before execution when wired into the agent runtime.`,
|
|
12
|
+
`${brand} provides decision journals, evidence gates, and workflow hardening for agentic teams.`,
|
|
13
|
+
];
|
|
14
|
+
return {
|
|
15
|
+
brand,
|
|
16
|
+
canonicalUrl,
|
|
17
|
+
proofUrl,
|
|
18
|
+
entityClaims: claims,
|
|
19
|
+
fragments: claims.map((claim, index) => ({
|
|
20
|
+
id: `thumbgate_entity_fragment_${index + 1}`,
|
|
21
|
+
text: claim,
|
|
22
|
+
schemaHint: 'SoftwareApplication',
|
|
23
|
+
proofUrl,
|
|
24
|
+
})),
|
|
25
|
+
distributionSurfaces: [
|
|
26
|
+
'public/llm-context.md',
|
|
27
|
+
'README.md',
|
|
28
|
+
'GitHub About',
|
|
29
|
+
'npm package description',
|
|
30
|
+
'LinkedIn post',
|
|
31
|
+
'newsletter/webinar page',
|
|
32
|
+
'comparison pages',
|
|
33
|
+
],
|
|
34
|
+
measurement: {
|
|
35
|
+
primary: ['AI citations', 'branded search mentions', 'LLM recommendation presence'],
|
|
36
|
+
secondary: ['referral clicks', 'checkout starts', 'workflow sprint leads'],
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports = {
|
|
42
|
+
buildAiSearchDistributionPlan,
|
|
43
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
function normalizeText(value) {
|
|
5
|
+
if (value === undefined || value === null) return '';
|
|
6
|
+
return String(value).trim();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function normalizeTask(task, index = 0) {
|
|
10
|
+
const id = normalizeText(task?.id) || `task-${index + 1}`;
|
|
11
|
+
return {
|
|
12
|
+
id,
|
|
13
|
+
description: normalizeText(task?.description),
|
|
14
|
+
branchName: normalizeText(task?.branchName) || id.toLowerCase().replaceAll(/[^a-z0-9]+/g, '-'),
|
|
15
|
+
priority: Number.isFinite(Number(task?.priority)) ? Number(task.priority) : index + 1,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function buildArtifactAgentPlan(input = {}) {
|
|
20
|
+
const baselineName = normalizeText(input.baselineName) || 'baseline';
|
|
21
|
+
const gitUrl = normalizeText(input.gitUrl) || 'https://github.com/IgorGanapolsky/ThumbGate.git';
|
|
22
|
+
const tasks = Array.isArray(input.tasks) ? input.tasks.map(normalizeTask) : [];
|
|
23
|
+
const forks = tasks.map((task) => ({
|
|
24
|
+
taskId: task.id,
|
|
25
|
+
forkName: `${baselineName}-${task.id}`.toLowerCase().replaceAll(/[^a-z0-9-]+/g, '-'),
|
|
26
|
+
branchName: task.branchName,
|
|
27
|
+
artifactRemote: null,
|
|
28
|
+
tokenRef: `artifact_token_${task.id}`,
|
|
29
|
+
status: 'planned',
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
generatedAt: normalizeText(input.generatedAt) || new Date().toISOString(),
|
|
34
|
+
baseline: {
|
|
35
|
+
name: baselineName,
|
|
36
|
+
gitUrl,
|
|
37
|
+
importIfMissing: true,
|
|
38
|
+
},
|
|
39
|
+
taskSchema: {
|
|
40
|
+
required: ['id', 'description', 'branchName', 'priority'],
|
|
41
|
+
properties: {
|
|
42
|
+
id: 'stable task identifier',
|
|
43
|
+
description: 'agent-readable task description',
|
|
44
|
+
branchName: 'deterministic branch/fork suffix',
|
|
45
|
+
priority: 'lower number runs first',
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
tasks,
|
|
49
|
+
forks,
|
|
50
|
+
runnerContract: {
|
|
51
|
+
filesystem: 'in_memory_git',
|
|
52
|
+
tools: ['read(path)', 'write(path, contents)', 'run_tests(command)', 'commit(message)'],
|
|
53
|
+
constraints: [
|
|
54
|
+
'read before write',
|
|
55
|
+
'minimize changes',
|
|
56
|
+
'commit every successful task',
|
|
57
|
+
'never expose artifact tokens in logs',
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
reviewGate: {
|
|
61
|
+
requiredBeforeMerge: [
|
|
62
|
+
'diff summary',
|
|
63
|
+
'changed files',
|
|
64
|
+
'test output',
|
|
65
|
+
'decision journal entry',
|
|
66
|
+
'human or reviewer-agent approval',
|
|
67
|
+
],
|
|
68
|
+
blockedWithout: ['baseline comparison', 'rollback path', 'evidence artifacts'],
|
|
69
|
+
},
|
|
70
|
+
observability: {
|
|
71
|
+
events: ['task_created', 'fork_created', 'agent_started', 'tool_call', 'commit_pushed', 'reviewed', 'merged_or_rejected'],
|
|
72
|
+
metrics: ['task_latency_ms', 'tool_call_count', 'test_pass_rate', 'review_reject_rate'],
|
|
73
|
+
traceKey: 'artifact_task_id',
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
module.exports = {
|
|
79
|
+
buildArtifactAgentPlan,
|
|
80
|
+
normalizeTask,
|
|
81
|
+
};
|
package/scripts/billing.js
CHANGED
|
@@ -30,7 +30,6 @@ const {
|
|
|
30
30
|
resolveFallbackArtifactPath,
|
|
31
31
|
} = require('./feedback-paths');
|
|
32
32
|
const { getTelemetryAnalytics, getTelemetrySourceDiagnostics } = require('./telemetry-analytics');
|
|
33
|
-
const { loadWorkflowSprintLeads } = require('./workflow-sprint-intake');
|
|
34
33
|
const {
|
|
35
34
|
PRO_MONTHLY_PRICE_ID,
|
|
36
35
|
PRO_ANNUAL_PRICE_ID,
|
|
@@ -52,6 +51,12 @@ const {
|
|
|
52
51
|
const { ensureParentDir } = require('./fs-utils');
|
|
53
52
|
const mailer = require('./mailer');
|
|
54
53
|
|
|
54
|
+
function loadWorkflowSprintIntakeModule() {
|
|
55
|
+
const modulePath = path.resolve(__dirname, 'workflow-sprint-intake.js');
|
|
56
|
+
if (!fs.existsSync(modulePath)) return null;
|
|
57
|
+
return require(modulePath);
|
|
58
|
+
}
|
|
59
|
+
|
|
55
60
|
// ---------------------------------------------------------------------------
|
|
56
61
|
// Config
|
|
57
62
|
// ---------------------------------------------------------------------------
|
|
@@ -400,10 +405,23 @@ function resolveCheckoutBrandUrls(appOrigin) {
|
|
|
400
405
|
const origin = resolvePublicAppOrigin(appOrigin);
|
|
401
406
|
return {
|
|
402
407
|
icon: joinPublicUrl(origin, '/assets/brand/thumbgate-icon-512.png'),
|
|
408
|
+
iconPro: joinPublicUrl(origin, '/assets/brand/thumbgate-icon-pro-512.png'),
|
|
409
|
+
iconTeam: joinPublicUrl(origin, '/assets/brand/thumbgate-icon-team-512.png'),
|
|
403
410
|
logo: joinPublicUrl(origin, '/assets/brand/thumbgate-logo-1200x360.png'),
|
|
404
411
|
};
|
|
405
412
|
}
|
|
406
413
|
|
|
414
|
+
// Resolve the per-tier product image that ships to Stripe `product_data.images`.
|
|
415
|
+
// Keeping three distinct URLs means the Stripe dashboard and checkout surface
|
|
416
|
+
// never show twins for Free/Pro/Team; see tests/billing-tier-icons.test.js.
|
|
417
|
+
function resolveTierIconUrl(planId, appOrigin) {
|
|
418
|
+
const brandUrls = resolveCheckoutBrandUrls(appOrigin);
|
|
419
|
+
const normalized = typeof planId === 'string' ? planId.toLowerCase() : '';
|
|
420
|
+
if (normalized === 'team') return brandUrls.iconTeam;
|
|
421
|
+
if (normalized === 'pro') return brandUrls.iconPro;
|
|
422
|
+
return brandUrls.icon;
|
|
423
|
+
}
|
|
424
|
+
|
|
407
425
|
function buildCheckoutBrandingSettings(appOrigin) {
|
|
408
426
|
const brandUrls = resolveCheckoutBrandUrls(appOrigin);
|
|
409
427
|
return {
|
|
@@ -419,12 +437,11 @@ function buildCheckoutBrandingSettings(appOrigin) {
|
|
|
419
437
|
};
|
|
420
438
|
}
|
|
421
439
|
|
|
422
|
-
function buildCheckoutProductData({ name, description, appOrigin }) {
|
|
423
|
-
const brandUrls = resolveCheckoutBrandUrls(appOrigin);
|
|
440
|
+
function buildCheckoutProductData({ name, description, appOrigin, planId }) {
|
|
424
441
|
return {
|
|
425
442
|
name,
|
|
426
443
|
description,
|
|
427
|
-
images: [
|
|
444
|
+
images: [resolveTierIconUrl(planId, appOrigin)],
|
|
428
445
|
};
|
|
429
446
|
}
|
|
430
447
|
|
|
@@ -443,9 +460,10 @@ function buildSubscriptionPriceData(checkoutSelection, appOrigin) {
|
|
|
443
460
|
product_data: buildCheckoutProductData({
|
|
444
461
|
name: isTeam ? 'ThumbGate Team' : 'ThumbGate Pro',
|
|
445
462
|
description: isTeam
|
|
446
|
-
? 'Shared Pre-Action
|
|
447
|
-
: 'Local dashboard, DPO export, and Pre-Action
|
|
463
|
+
? 'Shared Pre-Action Checks, team governance, and workflow hardening for AI coding agents.'
|
|
464
|
+
: 'Local dashboard, DPO export, and Pre-Action Checks for AI coding agents.',
|
|
448
465
|
appOrigin,
|
|
466
|
+
planId: isTeam ? 'team' : 'pro',
|
|
449
467
|
}),
|
|
450
468
|
};
|
|
451
469
|
}
|
|
@@ -516,7 +534,7 @@ function buildTrialActivationEmail({ customerEmail, apiKey, sessionId, planId, a
|
|
|
516
534
|
const subject = 'Your 7-day ThumbGate Pro trial is live';
|
|
517
535
|
const preheader = 'Activate Pro in one command, open the dashboard, and start blocking repeated AI coding mistakes.';
|
|
518
536
|
const headline = 'Your 7-day ThumbGate Pro trial is live.';
|
|
519
|
-
const intro = 'ThumbGate turns thumbs up/down feedback into Pre-Action
|
|
537
|
+
const intro = 'ThumbGate turns thumbs up/down feedback into Pre-Action Checks that stop repeated AI coding mistakes before the next tool call. It keeps lessons local and turns repeated mistakes into Reliability Gateway blocks.';
|
|
520
538
|
const exampleFeedback = 'thumbs down: the answer skipped exact files and tests; next time include paths, commands, and verification evidence.';
|
|
521
539
|
const safeDashboardUrl = escapeHtml(dashboardUrl);
|
|
522
540
|
const safeDocsUrl = escapeHtml(docsUrl);
|
|
@@ -1759,8 +1777,9 @@ function getBusinessAnalytics(options = {}) {
|
|
|
1759
1777
|
(entry) => entry && entry.timestamp
|
|
1760
1778
|
);
|
|
1761
1779
|
const revenueEvents = loadResolvedRevenueEvents({ ...analyticsWindow, extraRevenueEvents });
|
|
1780
|
+
const workflowSprintIntake = loadWorkflowSprintIntakeModule();
|
|
1762
1781
|
const workflowSprintLeads = filterEntriesForWindow(
|
|
1763
|
-
loadWorkflowSprintLeads(),
|
|
1782
|
+
workflowSprintIntake ? workflowSprintIntake.loadWorkflowSprintLeads() : [],
|
|
1764
1783
|
analyticsWindow,
|
|
1765
1784
|
(entry) => entry && entry.submittedAt
|
|
1766
1785
|
);
|
package/scripts/cli-feedback.js
CHANGED
|
@@ -73,7 +73,8 @@ function processInlineFeedback({ signal, context, chatHistory, whatWentWrong, wh
|
|
|
73
73
|
*/
|
|
74
74
|
function formatCliOutput(result) {
|
|
75
75
|
const lines = [];
|
|
76
|
-
const
|
|
76
|
+
const feedbackSignal = result.feedbackResult?.signal || result.feedbackResult?.feedbackEvent?.signal;
|
|
77
|
+
const isDown = ['down', 'negative', 'thumbs_down'].includes(feedbackSignal);
|
|
77
78
|
|
|
78
79
|
// Header
|
|
79
80
|
if (result.feedbackResult && result.feedbackResult.accepted !== false) {
|
package/scripts/cli-schema.js
CHANGED
|
@@ -10,6 +10,27 @@
|
|
|
10
10
|
* Groups: capture | discovery | gates | export | ops | advanced
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
function jsonFlag() {
|
|
14
|
+
return { name: 'json', type: 'boolean', description: 'Output as JSON' };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function discoveryCommand({
|
|
18
|
+
name,
|
|
19
|
+
aliases = [],
|
|
20
|
+
description,
|
|
21
|
+
mcpTool,
|
|
22
|
+
flags = [],
|
|
23
|
+
}) {
|
|
24
|
+
return {
|
|
25
|
+
name,
|
|
26
|
+
aliases,
|
|
27
|
+
description,
|
|
28
|
+
group: 'discovery',
|
|
29
|
+
...(mcpTool ? { mcpTool } : {}),
|
|
30
|
+
flags,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
13
34
|
const CLI_COMMANDS = [
|
|
14
35
|
// -------------------------------------------------------------------------
|
|
15
36
|
// Capture
|
|
@@ -71,7 +92,7 @@ const CLI_COMMANDS = [
|
|
|
71
92
|
},
|
|
72
93
|
{
|
|
73
94
|
name: 'gate-stats',
|
|
74
|
-
description: '
|
|
95
|
+
description: 'Check engine statistics — active checks, blocks, warns, time saved',
|
|
75
96
|
group: 'discovery',
|
|
76
97
|
flags: [
|
|
77
98
|
{ name: 'json', type: 'boolean', description: 'Output as JSON' },
|
|
@@ -99,14 +120,48 @@ const CLI_COMMANDS = [
|
|
|
99
120
|
{ name: 'json', type: 'boolean', description: 'Output as JSON' },
|
|
100
121
|
],
|
|
101
122
|
},
|
|
102
|
-
{
|
|
123
|
+
discoveryCommand({
|
|
103
124
|
name: 'doctor',
|
|
104
125
|
description: 'Audit runtime isolation, bootstrap context, and permission tier',
|
|
105
|
-
|
|
126
|
+
flags: [jsonFlag()],
|
|
127
|
+
}),
|
|
128
|
+
discoveryCommand({
|
|
129
|
+
name: 'harness-audit',
|
|
130
|
+
aliases: ['harness'],
|
|
131
|
+
description: 'Score global docs, MCP discovery, and specialized check harnesses',
|
|
106
132
|
flags: [
|
|
107
|
-
|
|
133
|
+
jsonFlag(),
|
|
134
|
+
{ name: 'doc-token-budget', type: 'number', description: 'Global docs budget (default 9000)' },
|
|
108
135
|
],
|
|
109
|
-
},
|
|
136
|
+
}),
|
|
137
|
+
discoveryCommand({
|
|
138
|
+
name: 'eval',
|
|
139
|
+
aliases: ['prompt-eval'],
|
|
140
|
+
description: 'Turn feedback into reusable prompt/workflow eval proof',
|
|
141
|
+
flags: [
|
|
142
|
+
jsonFlag(),
|
|
143
|
+
{ name: 'from-feedback', type: 'boolean', description: 'Generate eval cases from feedback-log.jsonl' },
|
|
144
|
+
{ name: 'feedback-log', type: 'string', description: 'Explicit feedback-log.jsonl path' },
|
|
145
|
+
{ name: 'feedback-dir', type: 'string', description: 'Explicit ThumbGate feedback directory' },
|
|
146
|
+
{ name: 'suite', type: 'string', description: 'Run an existing prompt eval suite' },
|
|
147
|
+
{ name: 'write-suite', type: 'string', description: 'Write generated suite JSON' },
|
|
148
|
+
{ name: 'write-report', type: 'string', description: 'Write Markdown proof report' },
|
|
149
|
+
{ name: 'min-score', type: 'number', description: 'Minimum passing score (default 80)' },
|
|
150
|
+
{ name: 'max-cases', type: 'number', description: 'Maximum feedback-derived cases (default 25)' },
|
|
151
|
+
],
|
|
152
|
+
}),
|
|
153
|
+
discoveryCommand({
|
|
154
|
+
name: 'native-messaging-audit',
|
|
155
|
+
aliases: ['bridge-audit'],
|
|
156
|
+
description: 'Audit local browser native messaging hosts and AI browser bridges',
|
|
157
|
+
mcpTool: 'native_messaging_audit',
|
|
158
|
+
flags: [
|
|
159
|
+
jsonFlag(),
|
|
160
|
+
{ name: 'platform', type: 'string', description: 'Override platform detection (darwin | linux | win32)' },
|
|
161
|
+
{ name: 'home-dir', type: 'string', description: 'Override home directory for manifest discovery' },
|
|
162
|
+
{ name: 'ai-only', type: 'boolean', description: 'Only report AI/browser bridge manifests' },
|
|
163
|
+
],
|
|
164
|
+
}),
|
|
110
165
|
{
|
|
111
166
|
name: 'lesson-health',
|
|
112
167
|
aliases: ['stale'],
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function estimateToolSchemaTokens(endpointCount, tokensPerEndpoint = 450) {
|
|
4
|
+
return Math.max(0, Number(endpointCount || 0) * Number(tokensPerEndpoint || 0));
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function buildCodeModeMcpPlan(options = {}) {
|
|
8
|
+
const endpointCount = Number(options.endpointCount || 0);
|
|
9
|
+
const traditionalTokens = estimateToolSchemaTokens(endpointCount, options.tokensPerEndpoint);
|
|
10
|
+
const codeModeTokens = Number(options.codeModeTokens || 1000);
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
pattern: 'code_mode_mcp',
|
|
14
|
+
endpointCount,
|
|
15
|
+
traditionalTokens,
|
|
16
|
+
codeModeTokens,
|
|
17
|
+
tokenReductionPercent: traditionalTokens > 0
|
|
18
|
+
? Number((((traditionalTokens - codeModeTokens) / traditionalTokens) * 100).toFixed(2))
|
|
19
|
+
: 0,
|
|
20
|
+
tools: [
|
|
21
|
+
{
|
|
22
|
+
name: 'search',
|
|
23
|
+
purpose: 'Find the relevant API area, path, operation, or type without loading the whole schema into context.',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: 'execute',
|
|
27
|
+
purpose: 'Run a bounded code snippet against typed API helpers inside a sandbox.',
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
sandbox: {
|
|
31
|
+
filesystem: 'none',
|
|
32
|
+
environmentVariables: 'not_exposed',
|
|
33
|
+
outboundRequests: 'explicit_handlers_only',
|
|
34
|
+
maxExecutionMs: Number(options.maxExecutionMs || 10000),
|
|
35
|
+
},
|
|
36
|
+
gates: [
|
|
37
|
+
'search before execute',
|
|
38
|
+
'execute only against typed helper SDK',
|
|
39
|
+
'block raw credential access',
|
|
40
|
+
'record code snippet and API calls in audit log',
|
|
41
|
+
'require idempotency key for write operations',
|
|
42
|
+
],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function evaluateCodeModeMcpPlan(plan = {}) {
|
|
47
|
+
const issues = [];
|
|
48
|
+
if (Number(plan.endpointCount || 0) < 100) issues.push('api_surface_too_small_for_code_mode');
|
|
49
|
+
if (!Array.isArray(plan.tools) || plan.tools.length !== 2) issues.push('expected_search_and_execute_only');
|
|
50
|
+
if (plan.sandbox?.filesystem !== 'none') issues.push('filesystem_must_be_disabled');
|
|
51
|
+
if (plan.sandbox?.environmentVariables !== 'not_exposed') issues.push('env_vars_must_not_be_exposed');
|
|
52
|
+
if (plan.sandbox?.outboundRequests !== 'explicit_handlers_only') issues.push('outbound_requests_need_handlers');
|
|
53
|
+
if (!Array.isArray(plan.gates) || !plan.gates.includes('search before execute')) {
|
|
54
|
+
issues.push('search_before_execute_required');
|
|
55
|
+
}
|
|
56
|
+
if (!Array.isArray(plan.gates) || !plan.gates.includes('require idempotency key for write operations')) {
|
|
57
|
+
issues.push('write_idempotency_required');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
decision: issues.length ? 'warn' : 'allow',
|
|
62
|
+
issues,
|
|
63
|
+
tokenReductionPercent: plan.tokenReductionPercent || 0,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
module.exports = {
|
|
68
|
+
buildCodeModeMcpPlan,
|
|
69
|
+
estimateToolSchemaTokens,
|
|
70
|
+
evaluateCodeModeMcpPlan,
|
|
71
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const PRO_MONTHLY_PAYMENT_LINK = 'https://
|
|
3
|
+
const PRO_MONTHLY_PAYMENT_LINK = 'https://thumbgate-production.up.railway.app/go/pro?utm_source=offer';
|
|
4
4
|
const PRO_ANNUAL_PAYMENT_LINK = 'https://buy.stripe.com/3cI8wPfCYaPs2dzdKz3sI07';
|
|
5
5
|
|
|
6
6
|
const PRO_MONTHLY_PRICE_ID = 'price_1THQY7GGBpd520QYHoS7RG0J';
|
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
* topical bundles and route queries to the most relevant subset. This reduces
|
|
10
10
|
* MCP tool calls and context window consumption.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
* Ported from Subway_RN_Demo/scripts/context-engine.js for thumbgate.
|
|
12
|
+
* Context assembly engine for ThumbGate feedback memory.
|
|
14
13
|
* PATH: PROJECT_ROOT = path.join(__dirname, '..') — 1 level up from scripts/
|
|
15
14
|
*/
|
|
16
15
|
|
|
@@ -26,7 +26,10 @@ const {
|
|
|
26
26
|
readSessionHandoff,
|
|
27
27
|
recordProvenance,
|
|
28
28
|
} = require('./contextfs');
|
|
29
|
-
const {
|
|
29
|
+
const { loadOptionalModule } = require('./private-core-boundary');
|
|
30
|
+
const { retrieveRelevantLessons } = loadOptionalModule('./lesson-retrieval', () => ({
|
|
31
|
+
retrieveRelevantLessons: () => [],
|
|
32
|
+
}));
|
|
30
33
|
const { evaluatePretool } = require('./hybrid-feedback-context');
|
|
31
34
|
const { loadProfile } = require('./user-profile');
|
|
32
35
|
const {
|