thumbgate 1.15.0 → 1.16.1
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 +59 -35
- package/adapters/chatgpt/openapi.yaml +118 -2
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/mcp/server-stdio.js +210 -84
- package/adapters/opencode/opencode.json +1 -1
- package/bench/prompt-eval-suite.json +5 -1
- package/bin/cli.js +157 -8
- package/config/evals/agent-safety-eval.json +338 -22
- package/config/gates/routine.json +43 -0
- package/config/github-about.json +3 -3
- package/config/model-candidates.json +131 -0
- package/openapi/openapi.yaml +118 -2
- package/package.json +57 -49
- package/public/blog.html +7 -7
- package/public/codex-plugin.html +6 -6
- package/public/compare.html +29 -23
- package/public/dashboard.html +82 -10
- package/public/guide.html +28 -28
- package/public/index.html +216 -98
- package/public/learn.html +50 -22
- package/public/lessons.html +1 -1
- package/public/numbers.html +17 -17
- package/public/pro.html +82 -18
- 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-schema.js +18 -2
- package/scripts/code-mode-mcp-plan.js +71 -0
- package/scripts/context-engine.js +1 -2
- package/scripts/context-manager.js +4 -1
- 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 +92 -4
- 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 +16 -4
- 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-inference.js +183 -44
- package/scripts/lesson-search.js +4 -1
- 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/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/private-core-boundary.js +72 -0
- package/scripts/production-agent-readiness.js +40 -0
- package/scripts/prompt-eval.js +564 -32
- package/scripts/prompt-programs.js +93 -0
- package/scripts/provider-action-normalizer.js +585 -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 +232 -55
- 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 +63 -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/src/api/server.js +381 -120
- 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
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const MEMORY_TYPES = new Set(['episodic', 'semantic', 'procedural', 'preference', 'working']);
|
|
5
|
+
|
|
6
|
+
function normalizeText(value) {
|
|
7
|
+
if (value === undefined || value === null) return '';
|
|
8
|
+
return String(value).trim();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function normalizeMemoryType(value) {
|
|
12
|
+
const normalized = normalizeText(value).toLowerCase();
|
|
13
|
+
return MEMORY_TYPES.has(normalized) ? normalized : 'episodic';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function buildMemoryLifecyclePolicy(input = {}) {
|
|
17
|
+
return {
|
|
18
|
+
generatedAt: normalizeText(input.generatedAt) || new Date().toISOString(),
|
|
19
|
+
memoryTypes: [
|
|
20
|
+
{
|
|
21
|
+
type: 'working',
|
|
22
|
+
purpose: 'Short-lived task context.',
|
|
23
|
+
retention: 'session',
|
|
24
|
+
promotionGate: 'discard unless referenced by outcome evidence',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
type: 'episodic',
|
|
28
|
+
purpose: 'Specific agent actions, feedback, and outcomes.',
|
|
29
|
+
retention: 'bounded_history',
|
|
30
|
+
promotionGate: 'requires actionable context and source trace',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
type: 'semantic',
|
|
34
|
+
purpose: 'Consolidated facts, standards, and reusable lessons.',
|
|
35
|
+
retention: 'durable',
|
|
36
|
+
promotionGate: 'requires deduplication and contradiction check',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
type: 'procedural',
|
|
40
|
+
purpose: 'Reusable workflows, prompt programs, and gates.',
|
|
41
|
+
retention: 'durable',
|
|
42
|
+
promotionGate: 'requires test or replay evidence',
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
type: 'preference',
|
|
46
|
+
purpose: 'Operator style and decision preferences.',
|
|
47
|
+
retention: 'durable_redactable',
|
|
48
|
+
promotionGate: 'requires explicit user signal',
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
retrieval: {
|
|
52
|
+
defaultTopK: 8,
|
|
53
|
+
recencyWeight: 0.25,
|
|
54
|
+
semanticWeight: 0.5,
|
|
55
|
+
outcomeWeight: 0.25,
|
|
56
|
+
requireSourceAnchors: true,
|
|
57
|
+
},
|
|
58
|
+
privacy: {
|
|
59
|
+
piiScanRequired: true,
|
|
60
|
+
secretScanRequired: true,
|
|
61
|
+
exportRequiresRedaction: true,
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function evaluateMemoryPromotion(memory = {}, policy = buildMemoryLifecyclePolicy()) {
|
|
67
|
+
const type = normalizeMemoryType(memory.type);
|
|
68
|
+
const content = normalizeText(memory.content);
|
|
69
|
+
const source = normalizeText(memory.source);
|
|
70
|
+
const outcome = normalizeText(memory.outcome);
|
|
71
|
+
const issues = [];
|
|
72
|
+
|
|
73
|
+
if (!content) issues.push('missing_content');
|
|
74
|
+
if (!source) issues.push('missing_source_anchor');
|
|
75
|
+
if (type !== 'preference' && !outcome) issues.push('missing_outcome');
|
|
76
|
+
if (/api[_-]?key|secret|password|token|bearer\s+[a-z0-9._-]+/i.test(content)) {
|
|
77
|
+
issues.push('secret_like_content');
|
|
78
|
+
}
|
|
79
|
+
if (type === 'preference' && memory.explicitUserSignal !== true) {
|
|
80
|
+
issues.push('preference_without_explicit_signal');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
type,
|
|
85
|
+
decision: issues.length === 0 ? 'promote' : 'hold',
|
|
86
|
+
issues,
|
|
87
|
+
retrievalEligible: issues.length === 0 || !issues.includes('secret_like_content'),
|
|
88
|
+
policyVersion: policy.generatedAt,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
module.exports = {
|
|
93
|
+
buildMemoryLifecyclePolicy,
|
|
94
|
+
evaluateMemoryPromotion,
|
|
95
|
+
normalizeMemoryType,
|
|
96
|
+
};
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const DEFAULT_CHECKS = [
|
|
4
|
+
{
|
|
5
|
+
id: 'robots_ai_rules',
|
|
6
|
+
category: 'discoverability',
|
|
7
|
+
artifact: 'public/robots.txt',
|
|
8
|
+
requirement: 'Declare sitemap and AI bot access policy.',
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
id: 'sitemap',
|
|
12
|
+
category: 'discoverability',
|
|
13
|
+
artifact: 'public/sitemap.xml',
|
|
14
|
+
requirement: 'Expose canonical public pages for crawlers and AI agents.',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: 'markdown_negotiation',
|
|
18
|
+
category: 'content_accessibility',
|
|
19
|
+
artifact: 'public/llm-context.md',
|
|
20
|
+
requirement: 'Offer dense Markdown context for agents that prefer text-first retrieval.',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: 'mcp_server_card',
|
|
24
|
+
category: 'protocol_discovery',
|
|
25
|
+
artifact: 'public/.well-known/mcp-server.json',
|
|
26
|
+
requirement: 'Publish MCP discovery metadata for agent tools.',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: 'agent_skills',
|
|
30
|
+
category: 'protocol_discovery',
|
|
31
|
+
artifact: 'public/.well-known/agent-skills.json',
|
|
32
|
+
requirement: 'Describe callable skills and evidence requirements.',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: 'oauth_protected_resource',
|
|
36
|
+
category: 'api_auth',
|
|
37
|
+
artifact: 'public/.well-known/oauth-protected-resource',
|
|
38
|
+
requirement: 'Advertise protected API resource metadata when authenticated tools exist.',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: 'agentic_commerce',
|
|
42
|
+
category: 'commerce',
|
|
43
|
+
artifact: 'public/.well-known/agentic-commerce.json',
|
|
44
|
+
requirement: 'Expose paid plan, checkout, refund, and support metadata for commerce agents.',
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
function normalizeExisting(existing = []) {
|
|
49
|
+
if (Array.isArray(existing)) return new Set(existing);
|
|
50
|
+
return new Set(Object.entries(existing).filter(([, present]) => present).map(([id]) => id));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function buildAgentReadinessPlan(options = {}) {
|
|
54
|
+
const baseUrl = options.baseUrl || 'https://thumbgate-production.up.railway.app';
|
|
55
|
+
const existing = normalizeExisting(options.existing);
|
|
56
|
+
const checks = (options.checks || DEFAULT_CHECKS).map((check) => {
|
|
57
|
+
const present = existing.has(check.id) || existing.has(check.artifact);
|
|
58
|
+
return {
|
|
59
|
+
...check,
|
|
60
|
+
status: present ? 'present' : 'missing',
|
|
61
|
+
url: check.artifact.startsWith('public/')
|
|
62
|
+
? `${baseUrl}/${check.artifact.replace(/^public\//, '')}`
|
|
63
|
+
: `${baseUrl}/${check.artifact}`,
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
const missing = checks.filter((check) => check.status === 'missing');
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
baseUrl,
|
|
70
|
+
score: Math.round(((checks.length - missing.length) / checks.length) * 100),
|
|
71
|
+
checks,
|
|
72
|
+
quickWins: missing
|
|
73
|
+
.filter((check) => ['discoverability', 'content_accessibility', 'protocol_discovery'].includes(check.category))
|
|
74
|
+
.slice(0, 5)
|
|
75
|
+
.map((check) => ({
|
|
76
|
+
id: check.id,
|
|
77
|
+
action: `publish ${check.artifact}`,
|
|
78
|
+
reason: check.requirement,
|
|
79
|
+
})),
|
|
80
|
+
promotionAngles: [
|
|
81
|
+
'agent-ready pre-action gates',
|
|
82
|
+
'MCP-discoverable reliability gateway',
|
|
83
|
+
'machine-readable evidence before agent actions',
|
|
84
|
+
'commerce metadata for paid operator lanes',
|
|
85
|
+
],
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function evaluateAgentReadinessPlan(plan) {
|
|
90
|
+
const issues = [];
|
|
91
|
+
const required = [
|
|
92
|
+
'robots_ai_rules',
|
|
93
|
+
'sitemap',
|
|
94
|
+
'markdown_negotiation',
|
|
95
|
+
'mcp_server_card',
|
|
96
|
+
];
|
|
97
|
+
const byId = new Map((plan.checks || []).map((check) => [check.id, check]));
|
|
98
|
+
|
|
99
|
+
for (const id of required) {
|
|
100
|
+
if (byId.get(id)?.status !== 'present') issues.push(`missing_${id}`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (!plan.baseUrl?.startsWith('https://')) {
|
|
104
|
+
issues.push('https_base_url_required');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
decision: issues.length ? 'warn' : 'allow',
|
|
109
|
+
issues,
|
|
110
|
+
score: plan.score || 0,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
module.exports = {
|
|
115
|
+
DEFAULT_CHECKS,
|
|
116
|
+
buildAgentReadinessPlan,
|
|
117
|
+
evaluateAgentReadinessPlan,
|
|
118
|
+
};
|
|
@@ -17,7 +17,27 @@ const {
|
|
|
17
17
|
serializeAnalyticsWindow,
|
|
18
18
|
} = require('./analytics-window');
|
|
19
19
|
const { appendWorkflowRun } = require('./workflow-runs');
|
|
20
|
-
const {
|
|
20
|
+
const {
|
|
21
|
+
createUnavailableReport,
|
|
22
|
+
loadOptionalModule,
|
|
23
|
+
} = require('./private-core-boundary');
|
|
24
|
+
const { buildPredictiveInsights } = loadOptionalModule('./predictive-insights', () => ({
|
|
25
|
+
buildPredictiveInsights: () => ({
|
|
26
|
+
opportunitySummary: [],
|
|
27
|
+
anomalySummary: { count: 0, severity: 'none' },
|
|
28
|
+
topCreators: [],
|
|
29
|
+
topSources: [],
|
|
30
|
+
upgradePropensity: {
|
|
31
|
+
pro: { band: 'unavailable', score: 0 },
|
|
32
|
+
team: { band: 'unavailable', score: 0 },
|
|
33
|
+
},
|
|
34
|
+
revenueForecast: {
|
|
35
|
+
predictedBookedRevenueCents: 0,
|
|
36
|
+
incrementalOpportunityCents: 0,
|
|
37
|
+
},
|
|
38
|
+
...createUnavailableReport('Predictive insights'),
|
|
39
|
+
}),
|
|
40
|
+
}));
|
|
21
41
|
const { ensureDir } = require('./fs-utils');
|
|
22
42
|
|
|
23
43
|
const PIPELINE_DIRNAME = 'agentic-data-pipeline';
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function buildAgentsSdkSandboxPlan(options = {}) {
|
|
4
|
+
const provider = options.provider || 'unix_local';
|
|
5
|
+
const mounts = options.mounts || [{ name: 'data', mode: 'read_only' }];
|
|
6
|
+
const outputDir = options.outputDir || 'outputs';
|
|
7
|
+
|
|
8
|
+
return {
|
|
9
|
+
harness: 'openai_agents_sdk_sandbox',
|
|
10
|
+
provider,
|
|
11
|
+
manifest: {
|
|
12
|
+
mounts,
|
|
13
|
+
outputDir,
|
|
14
|
+
network: options.network || 'disabled_by_default',
|
|
15
|
+
allowedCommands: options.allowedCommands || ['npm test', 'npm run test:coverage'],
|
|
16
|
+
},
|
|
17
|
+
separation: {
|
|
18
|
+
credentialsInSandbox: false,
|
|
19
|
+
toolBrokerOwnsSecrets: true,
|
|
20
|
+
sandboxGetsScopedFilesOnly: true,
|
|
21
|
+
},
|
|
22
|
+
durability: {
|
|
23
|
+
externalState: true,
|
|
24
|
+
checkpoints: ['manifest_loaded', 'tools_completed', 'patch_written', 'tests_run'],
|
|
25
|
+
rehydrateOnSandboxLoss: true,
|
|
26
|
+
},
|
|
27
|
+
gates: [
|
|
28
|
+
'read manifest before file access',
|
|
29
|
+
'write only under declared output or scoped repo path',
|
|
30
|
+
'cite source filenames for data-room answers',
|
|
31
|
+
'run configured verification before completion claim',
|
|
32
|
+
'persist decision journal outside sandbox',
|
|
33
|
+
],
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function evaluateSandboxPlan(plan = {}) {
|
|
38
|
+
const issues = [];
|
|
39
|
+
if (!plan.manifest?.mounts?.length) issues.push('missing_manifest_mounts');
|
|
40
|
+
if (!plan.manifest?.outputDir) issues.push('missing_output_dir');
|
|
41
|
+
if (plan.separation?.credentialsInSandbox !== false) issues.push('credentials_must_stay_outside_sandbox');
|
|
42
|
+
if (!plan.durability?.externalState) issues.push('external_state_required');
|
|
43
|
+
if (!plan.durability?.rehydrateOnSandboxLoss) issues.push('rehydration_required');
|
|
44
|
+
if (!Array.isArray(plan.gates) || !plan.gates.some((gate) => /verification/i.test(gate))) {
|
|
45
|
+
issues.push('verification_gate_required');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
decision: issues.length ? 'warn' : 'allow',
|
|
50
|
+
issues,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
module.exports = {
|
|
55
|
+
buildAgentsSdkSandboxPlan,
|
|
56
|
+
evaluateSandboxPlan,
|
|
57
|
+
};
|
|
@@ -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-schema.js
CHANGED
|
@@ -92,7 +92,7 @@ const CLI_COMMANDS = [
|
|
|
92
92
|
},
|
|
93
93
|
{
|
|
94
94
|
name: 'gate-stats',
|
|
95
|
-
description: '
|
|
95
|
+
description: 'Check engine statistics — active checks, blocks, warns, time saved',
|
|
96
96
|
group: 'discovery',
|
|
97
97
|
flags: [
|
|
98
98
|
{ name: 'json', type: 'boolean', description: 'Output as JSON' },
|
|
@@ -128,12 +128,28 @@ const CLI_COMMANDS = [
|
|
|
128
128
|
discoveryCommand({
|
|
129
129
|
name: 'harness-audit',
|
|
130
130
|
aliases: ['harness'],
|
|
131
|
-
description: 'Score global docs, MCP discovery, and specialized
|
|
131
|
+
description: 'Score global docs, MCP discovery, and specialized check harnesses',
|
|
132
132
|
flags: [
|
|
133
133
|
jsonFlag(),
|
|
134
134
|
{ name: 'doc-token-budget', type: 'number', description: 'Global docs budget (default 9000)' },
|
|
135
135
|
],
|
|
136
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
|
+
}),
|
|
137
153
|
discoveryCommand({
|
|
138
154
|
name: 'native-messaging-audit',
|
|
139
155
|
aliases: ['bridge-audit'],
|