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.
Files changed (150) hide show
  1. package/.claude-plugin/marketplace.json +6 -6
  2. package/.claude-plugin/plugin.json +3 -3
  3. package/.well-known/llms.txt +5 -5
  4. package/.well-known/mcp/server-card.json +1 -1
  5. package/README.md +60 -35
  6. package/adapters/chatgpt/openapi.yaml +118 -2
  7. package/adapters/claude/.mcp.json +2 -2
  8. package/adapters/mcp/server-stdio.js +217 -84
  9. package/adapters/opencode/opencode.json +1 -1
  10. package/bench/prompt-eval-suite.json +5 -1
  11. package/bin/cli.js +211 -8
  12. package/config/enforcement.json +59 -7
  13. package/config/evals/agent-safety-eval.json +338 -22
  14. package/config/gates/default.json +33 -0
  15. package/config/gates/routine.json +43 -0
  16. package/config/github-about.json +3 -3
  17. package/config/mcp-allowlists.json +4 -0
  18. package/config/merge-quality-checks.json +2 -1
  19. package/config/model-candidates.json +131 -0
  20. package/openapi/openapi.yaml +118 -2
  21. package/package.json +70 -51
  22. package/public/blog.html +7 -7
  23. package/public/codex-plugin.html +13 -7
  24. package/public/compare.html +29 -23
  25. package/public/dashboard.html +105 -12
  26. package/public/guide.html +28 -28
  27. package/public/index.html +233 -97
  28. package/public/learn.html +87 -20
  29. package/public/lessons.html +26 -2
  30. package/public/numbers.html +271 -0
  31. package/public/pro.html +89 -19
  32. package/scripts/agent-audit-trace.js +55 -0
  33. package/scripts/agent-memory-lifecycle.js +96 -0
  34. package/scripts/agent-readiness-plan.js +118 -0
  35. package/scripts/agentic-data-pipeline.js +21 -1
  36. package/scripts/agents-sdk-sandbox-plan.js +57 -0
  37. package/scripts/ai-org-governance.js +98 -0
  38. package/scripts/ai-search-distribution.js +43 -0
  39. package/scripts/artifact-agent-plan.js +81 -0
  40. package/scripts/billing.js +27 -8
  41. package/scripts/cli-feedback.js +2 -1
  42. package/scripts/cli-schema.js +60 -5
  43. package/scripts/code-mode-mcp-plan.js +71 -0
  44. package/scripts/commercial-offer.js +1 -1
  45. package/scripts/context-engine.js +1 -2
  46. package/scripts/context-manager.js +4 -1
  47. package/scripts/contextfs.js +214 -32
  48. package/scripts/dashboard-render-spec.js +1 -1
  49. package/scripts/dashboard.js +275 -9
  50. package/scripts/decision-journal.js +13 -3
  51. package/scripts/document-workflow-governance.js +62 -0
  52. package/scripts/enterprise-agent-rollout.js +34 -0
  53. package/scripts/experience-replay-governance.js +69 -0
  54. package/scripts/export-hf-dataset.js +1 -1
  55. package/scripts/feedback-loop.js +141 -9
  56. package/scripts/feedback-to-rules.js +17 -23
  57. package/scripts/gates-engine.js +4 -6
  58. package/scripts/growth-campaigns.js +49 -0
  59. package/scripts/harness-selector.js +145 -1
  60. package/scripts/hybrid-supervisor-agent.js +64 -0
  61. package/scripts/inference-cache-policy.js +72 -0
  62. package/scripts/inference-economics.js +53 -0
  63. package/scripts/internal-agent-bootstrap.js +12 -2
  64. package/scripts/knowledge-layer-plan.js +108 -0
  65. package/scripts/lesson-canonical.js +181 -0
  66. package/scripts/lesson-db.js +71 -10
  67. package/scripts/lesson-inference.js +183 -44
  68. package/scripts/lesson-search.js +4 -1
  69. package/scripts/lesson-synthesis.js +23 -2
  70. package/scripts/llm-client.js +157 -26
  71. package/scripts/mailer/resend-mailer.js +112 -1
  72. package/scripts/mcp-transport-strategy.js +66 -0
  73. package/scripts/memory-store-governance.js +60 -0
  74. package/scripts/meta-agent-loop.js +7 -13
  75. package/scripts/model-access-eligibility.js +38 -0
  76. package/scripts/model-migration-readiness.js +55 -0
  77. package/scripts/native-messaging-audit.js +514 -0
  78. package/scripts/operational-integrity.js +96 -3
  79. package/scripts/otel-declarative-config.js +56 -0
  80. package/scripts/perplexity-client.js +1 -1
  81. package/scripts/post-training-governance.js +34 -0
  82. package/scripts/pr-manager.js +47 -7
  83. package/scripts/private-core-boundary.js +72 -0
  84. package/scripts/production-agent-readiness.js +40 -0
  85. package/scripts/profile-router.js +16 -1
  86. package/scripts/prompt-eval.js +564 -32
  87. package/scripts/prompt-programs.js +93 -0
  88. package/scripts/provider-action-normalizer.js +585 -0
  89. package/scripts/rule-validator.js +285 -0
  90. package/scripts/scaling-law-claims.js +60 -0
  91. package/scripts/security-scanner.js +1 -1
  92. package/scripts/self-distill-agent.js +7 -32
  93. package/scripts/seo-gsd.js +400 -43
  94. package/scripts/skill-rag-router.js +53 -0
  95. package/scripts/spec-gate.js +1 -1
  96. package/scripts/student-consistent-training.js +73 -0
  97. package/scripts/synthetic-data-provenance.js +98 -0
  98. package/scripts/task-context-result.js +81 -0
  99. package/scripts/telemetry-analytics.js +149 -0
  100. package/scripts/thompson-sampling.js +2 -2
  101. package/scripts/token-savings.js +7 -6
  102. package/scripts/token-tco.js +46 -0
  103. package/scripts/tool-registry.js +75 -3
  104. package/scripts/verification-loop.js +10 -1
  105. package/scripts/verifier-scoring.js +71 -0
  106. package/scripts/workflow-sentinel.js +284 -28
  107. package/scripts/workspace-agent-routines.js +118 -0
  108. package/skills/thumbgate/SKILL.md +1 -1
  109. package/src/api/server.js +434 -120
  110. package/.claude-plugin/README.md +0 -170
  111. package/adapters/README.md +0 -12
  112. package/scripts/analytics-report.js +0 -328
  113. package/scripts/autonomous-workflow.js +0 -377
  114. package/scripts/billing-setup.js +0 -109
  115. package/scripts/creator-campaigns.js +0 -239
  116. package/scripts/cross-encoder-reranker.js +0 -235
  117. package/scripts/daemon-manager.js +0 -108
  118. package/scripts/decision-trace.js +0 -354
  119. package/scripts/delegation-runtime.js +0 -896
  120. package/scripts/dispatch-brief.js +0 -159
  121. package/scripts/distribution-surfaces.js +0 -110
  122. package/scripts/feedback-history-distiller.js +0 -382
  123. package/scripts/funnel-analytics.js +0 -35
  124. package/scripts/history-distiller.js +0 -200
  125. package/scripts/hosted-job-launcher.js +0 -256
  126. package/scripts/intent-router.js +0 -392
  127. package/scripts/lesson-reranker.js +0 -263
  128. package/scripts/lesson-retrieval.js +0 -148
  129. package/scripts/managed-lesson-agent.js +0 -183
  130. package/scripts/operational-dashboard.js +0 -103
  131. package/scripts/operational-summary.js +0 -129
  132. package/scripts/operator-artifacts.js +0 -608
  133. package/scripts/optimize-context.js +0 -17
  134. package/scripts/org-dashboard.js +0 -206
  135. package/scripts/partner-orchestration.js +0 -146
  136. package/scripts/predictive-insights.js +0 -356
  137. package/scripts/pulse.js +0 -80
  138. package/scripts/reflector-agent.js +0 -221
  139. package/scripts/sales-pipeline.js +0 -681
  140. package/scripts/session-episode-store.js +0 -329
  141. package/scripts/session-health-sensor.js +0 -242
  142. package/scripts/session-report.js +0 -120
  143. package/scripts/swarm-coordinator.js +0 -81
  144. package/scripts/tool-kpi-tracker.js +0 -12
  145. package/scripts/webhook-delivery.js +0 -62
  146. package/scripts/workflow-sprint-intake.js +0 -475
  147. package/skills/agent-memory/SKILL.md +0 -97
  148. package/skills/solve-architecture-autonomy/SKILL.md +0 -17
  149. package/skills/solve-architecture-autonomy/tool.js +0 -33
  150. package/skills/thumbgate-feedback/SKILL.md +0 -49
@@ -110,7 +110,7 @@ function extractCitations(response) {
110
110
 
111
111
  class PerplexityClient {
112
112
  constructor(options = {}) {
113
- this.apiKey = options.apiKey || process.env.PERPLEXITY_API_KEY || '';
113
+ this.apiKey = options.apiKey ?? process.env.PERPLEXITY_API_KEY ?? '';
114
114
  this.baseUrl = options.baseUrl || process.env.PERPLEXITY_BASE_URL || DEFAULT_BASE_URL;
115
115
  this.fetchFn = options.fetchFn || globalThis.fetch;
116
116
  this.timeoutMs = Number(options.timeoutMs || process.env.PERPLEXITY_TIMEOUT_MS || DEFAULT_TIMEOUT_MS);
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ function evaluatePostTrainingPlan(input = {}) {
5
+ const mode = String(input.mode || '').toLowerCase();
6
+ const issues = [];
7
+ if (!['sft', 'rl', 'grpo', 'gspo'].includes(mode)) issues.push('unsupported_post_training_mode');
8
+ if (!input.dataset) issues.push('missing_dataset');
9
+ if (!input.baseCheckpoint) issues.push('missing_base_checkpoint');
10
+ if (input.piiRedacted !== true) issues.push('pii_redaction_required');
11
+ if (input.holdoutEval !== true) issues.push('holdout_eval_required');
12
+ if (input.rewardSpecRequired !== false && ['rl', 'grpo', 'gspo'].includes(mode) && !input.rewardSpec) {
13
+ issues.push('missing_reward_spec');
14
+ }
15
+ if (input.maxSpendCents === undefined) issues.push('missing_spend_cap');
16
+
17
+ return {
18
+ mode,
19
+ decision: issues.length === 0 ? 'allow' : 'warn',
20
+ issues,
21
+ requiredArtifacts: [
22
+ 'dataset manifest',
23
+ 'PII redaction report',
24
+ 'base checkpoint',
25
+ 'holdout eval report',
26
+ 'spend cap',
27
+ ['rl', 'grpo', 'gspo'].includes(mode) ? 'reward specification' : null,
28
+ ].filter(Boolean),
29
+ };
30
+ }
31
+
32
+ module.exports = {
33
+ evaluatePostTrainingPlan,
34
+ };
@@ -90,9 +90,18 @@ function resolveGhBinary(options = {}) {
90
90
  throw new Error(`Unable to locate GH CLI in fixed paths: ${candidates.join(', ')}`);
91
91
  }
92
92
 
93
+ function buildGhEnv(baseEnv = process.env) {
94
+ const env = { ...baseEnv };
95
+ if (!env.GH_TOKEN && !env.GITHUB_TOKEN && env.GH_PAT) {
96
+ env.GH_TOKEN = env.GH_PAT;
97
+ }
98
+ return env;
99
+ }
100
+
93
101
  function runGh(args, options = {}) {
94
102
  return spawnSync(resolveGhBinary(options), assertSafeGhArgs(args), {
95
103
  encoding: 'utf-8',
104
+ env: buildGhEnv(options.env || process.env),
96
105
  stdio: ['ignore', 'pipe', 'pipe'],
97
106
  });
98
107
  }
@@ -154,7 +163,8 @@ function isOpenPr(pr) {
154
163
 
155
164
  function loadManagedPrs(prNumber = '', runner = runGh) {
156
165
  if (prNumber) {
157
- return [getPrStatus(prNumber, runner)];
166
+ const explicitPr = getPrStatus(prNumber, runner);
167
+ return isOpenPr(explicitPr) ? [explicitPr] : [];
158
168
  }
159
169
 
160
170
  const currentBranchPr = getPrStatus('', runner);
@@ -336,11 +346,40 @@ function waitForMergeCommit(prNumber, runner = runGh, options = {}) {
336
346
  };
337
347
  }
338
348
 
349
+ function submitTrunkMergeRequest(prNumber, runner = runGh) {
350
+ const normalizedPrNumber = normalizePrNumber(prNumber, { allowEmpty: false });
351
+ const args = ['pr', 'comment', normalizedPrNumber, '--body', '/trunk merge'];
352
+ console.log(`[PR Manager] Requesting Trunk merge queue for PR #${normalizedPrNumber}...`);
353
+ const result = runner(args);
354
+ if (result.status !== 0) {
355
+ console.error(`[PR Manager] Queue request failed: ${formatGhError(result)}`);
356
+ return { ok: false, mode: 'failed', args, error: formatGhError(result) };
357
+ }
358
+
359
+ console.log(`[PR Manager] Queue request accepted for PR #${normalizedPrNumber} (/trunk merge).`);
360
+ return {
361
+ ok: true,
362
+ mode: 'queued',
363
+ args,
364
+ finalized: false,
365
+ merged: false,
366
+ reason: 'merge_commit_pending',
367
+ };
368
+ }
369
+
339
370
  /**
340
371
  * Perform autonomous merge
341
372
  */
342
- function performMerge(prNumber, runner = runGh, options = {}) {
343
- const normalizedPrNumber = normalizePrNumber(prNumber, { allowEmpty: false });
373
+ function performMerge(prInput, runner = runGh, options = {}) {
374
+ const pr = (prInput && typeof prInput === 'object')
375
+ ? prInput
376
+ : { number: prInput, baseRefName: options.baseRefName || '' };
377
+ const normalizedPrNumber = normalizePrNumber(pr.number, { allowEmpty: false });
378
+
379
+ if (String(pr.baseRefName || '').toLowerCase() === 'main') {
380
+ return submitTrunkMergeRequest(normalizedPrNumber, runner);
381
+ }
382
+
344
383
  const args = ['pr', 'merge', normalizedPrNumber, '--squash', '--delete-branch'];
345
384
  console.log(`[PR Manager] Initiating protected squash merge for PR #${normalizedPrNumber}...`);
346
385
  const result = runner(args);
@@ -352,10 +391,10 @@ function performMerge(prNumber, runner = runGh, options = {}) {
352
391
  ? { finalized: false, merged: false, reason: 'merge_commit_pending' }
353
392
  : waitForMergeCommit(normalizedPrNumber, runner, options);
354
393
  return { ok: true, mode, args, ...mergeStatus };
355
- } else {
356
- console.error(`[PR Manager] Merge failed: ${formatGhError(result)}`);
357
- return { ok: false, mode: 'failed', args, error: formatGhError(result) };
358
394
  }
395
+
396
+ console.error(`[PR Manager] Merge failed: ${formatGhError(result)}`);
397
+ return { ok: false, mode: 'failed', args, error: formatGhError(result) };
359
398
  }
360
399
 
361
400
  async function managePrs(prNumber = '', runner = runGh, options = {}) {
@@ -370,7 +409,7 @@ async function managePrs(prNumber = '', runner = runGh, options = {}) {
370
409
  for (const pr of prs) {
371
410
  const outcome = await resolveBlockers(pr, runner);
372
411
  if (outcome.status === 'ready') {
373
- const mergeResult = performMerge(pr.number, runner, options);
412
+ const mergeResult = performMerge(pr, runner, options);
374
413
  outcome.mergeRequested = mergeResult.ok;
375
414
  outcome.mergeMode = mergeResult.mode;
376
415
  if (mergeResult.mergeCommit) {
@@ -406,6 +445,7 @@ if (require.main === module) {
406
445
 
407
446
  module.exports = {
408
447
  assertSafeGhArgs,
448
+ buildGhEnv,
409
449
  getPrStatus,
410
450
  getPrChecks,
411
451
  listOpenPrs,
@@ -0,0 +1,72 @@
1
+ 'use strict';
2
+
3
+ const path = require('node:path');
4
+
5
+ function normalizeRequest(request) {
6
+ return String(request || '').trim();
7
+ }
8
+
9
+ function isOptionalModuleMissing(error, request) {
10
+ if (!error || error.code !== 'MODULE_NOT_FOUND') {
11
+ return false;
12
+ }
13
+ const message = String(error?.message || '');
14
+ const normalizedRequest = normalizeRequest(request);
15
+ const basename = path.basename(normalizedRequest);
16
+ return [normalizedRequest, basename]
17
+ .filter(Boolean)
18
+ .some((candidate) => message.includes(candidate));
19
+ }
20
+
21
+ function loadOptionalModule(request, fallbackFactory) {
22
+ try {
23
+ return require(request);
24
+ } catch (error) {
25
+ if (!isOptionalModuleMissing(error, request)) {
26
+ throw error;
27
+ }
28
+ return typeof fallbackFactory === 'function'
29
+ ? fallbackFactory(error)
30
+ : (fallbackFactory || {});
31
+ }
32
+ }
33
+
34
+ function createUnavailableError(feature, options = {}) {
35
+ const err = new Error(
36
+ `${feature} moved behind the ThumbGate-Core boundary and is unavailable in the public thumbgate package.`
37
+ );
38
+ err.code = 'THUMBGATE_CORE_REQUIRED';
39
+ err.statusCode = options.statusCode || 503;
40
+ err.feature = feature;
41
+ return err;
42
+ }
43
+
44
+ function createUnavailableOperation(feature, options = {}) {
45
+ return function unavailableOperation() {
46
+ throw createUnavailableError(feature, options);
47
+ };
48
+ }
49
+
50
+ function createUnavailableAsyncOperation(feature, options = {}) {
51
+ return async function unavailableAsyncOperation() {
52
+ throw createUnavailableError(feature, options);
53
+ };
54
+ }
55
+
56
+ function createUnavailableReport(feature, extra = {}) {
57
+ return {
58
+ available: false,
59
+ source: 'ThumbGate-Core',
60
+ message: `${feature} requires ThumbGate-Core.`,
61
+ ...extra,
62
+ };
63
+ }
64
+
65
+ module.exports = {
66
+ createUnavailableAsyncOperation,
67
+ createUnavailableError,
68
+ createUnavailableOperation,
69
+ createUnavailableReport,
70
+ isOptionalModuleMissing,
71
+ loadOptionalModule,
72
+ };
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ function readinessStatus(score, missing) {
5
+ if (missing.length === 0) return 'production_ready';
6
+ if (score >= 60) return 'needs_hardening';
7
+ return 'prototype';
8
+ }
9
+
10
+ function evaluateProductionAgentReadiness(input = {}) {
11
+ const signals = {
12
+ subAgents: Array.isArray(input.subAgents) && input.subAgents.length >= 2,
13
+ structuredOutputs: input.structuredOutputs === true,
14
+ dynamicRag: input.dynamicRag === true,
15
+ observability: input.observability === true || input.tracing === true,
16
+ circuitBreakers: input.circuitBreakers === true,
17
+ };
18
+ const missing = Object.entries(signals)
19
+ .filter(([, present]) => !present)
20
+ .map(([name]) => name);
21
+ const score = Math.round((Object.values(signals).filter(Boolean).length / Object.keys(signals).length) * 100);
22
+ return {
23
+ status: readinessStatus(score, missing),
24
+ score,
25
+ signals,
26
+ missing,
27
+ requiredFixes: missing.map((name) => ({
28
+ subAgents: 'Split monolithic prompts into narrow sub-agent stages.',
29
+ structuredOutputs: 'Use runtime-validated schemas instead of prompt-only JSON formatting.',
30
+ dynamicRag: 'Replace hardcoded context with refreshed retrieval over indexed source material.',
31
+ observability: 'Emit traces for model calls, tool calls, tokens, latency, and stage failures.',
32
+ circuitBreakers: 'Set retry, timeout, loop, and spend limits before production use.',
33
+ }[name])),
34
+ };
35
+ }
36
+
37
+ module.exports = {
38
+ evaluateProductionAgentReadiness,
39
+ readinessStatus,
40
+ };
@@ -107,6 +107,15 @@ function loadProfilesLazy() {
107
107
  }
108
108
  }
109
109
 
110
+ const PROFILE_RESTRICTIVENESS_ORDER = Object.freeze([
111
+ 'locked',
112
+ 'readonly',
113
+ 'essential',
114
+ 'commerce',
115
+ 'dispatch',
116
+ 'default',
117
+ ]);
118
+
110
119
  /**
111
120
  * Find the most restrictive (smallest) profile that includes the given tool.
112
121
  * Profile restrictiveness = fewer tools allowed = more restricted.
@@ -114,11 +123,17 @@ function loadProfilesLazy() {
114
123
  function findMostRestrictiveProfile(toolName) {
115
124
  const policy = loadProfilesLazy();
116
125
  if (!policy || !policy.profiles) return null;
126
+ const profileRank = new Map(PROFILE_RESTRICTIVENESS_ORDER.map((name, index) => [name, index]));
117
127
 
118
128
  // Sort profiles by number of tools (most restrictive first)
119
129
  const candidates = Object.entries(policy.profiles)
120
130
  .filter(([, tools]) => tools.includes(toolName))
121
- .sort((a, b) => a[1].length - b[1].length);
131
+ .sort((a, b) => {
132
+ const sizeDelta = a[1].length - b[1].length;
133
+ if (sizeDelta !== 0) return sizeDelta;
134
+ return (profileRank.get(a[0]) ?? Number.MAX_SAFE_INTEGER)
135
+ - (profileRank.get(b[0]) ?? Number.MAX_SAFE_INTEGER);
136
+ });
122
137
 
123
138
  if (candidates.length === 0) return null;
124
139
  return candidates[0][0]; // most restrictive profile that has this tool