thumbgate 1.27.18 → 1.27.20

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 (170) hide show
  1. package/.claude/commands/dashboard.md +15 -0
  2. package/.claude/commands/thumbgate-blocked.md +27 -0
  3. package/.claude/commands/thumbgate-dashboard.md +15 -0
  4. package/.claude/commands/thumbgate-doctor.md +30 -0
  5. package/.claude/commands/thumbgate-guard.md +36 -0
  6. package/.claude/commands/thumbgate-protect.md +30 -0
  7. package/.claude/commands/thumbgate-rules.md +30 -0
  8. package/.claude-plugin/plugin.json +4 -3
  9. package/.well-known/agentic-verify.txt +1 -0
  10. package/.well-known/llms.txt +33 -12
  11. package/.well-known/mcp/server-card.json +8 -8
  12. package/README.md +246 -30
  13. package/adapters/claude/.mcp.json +2 -2
  14. package/adapters/codex/config.toml +2 -2
  15. package/adapters/gcp/dfcx-webhook-gate.js +295 -0
  16. package/adapters/gemini/function-declarations.json +1 -0
  17. package/adapters/letta/README.md +41 -0
  18. package/adapters/letta/thumbgate-letta-adapter.js +133 -0
  19. package/adapters/mcp/server-stdio.js +263 -11
  20. package/adapters/opencode/opencode.json +1 -1
  21. package/adapters/policy-engine/ethicore-guardian-client.js +68 -0
  22. package/adapters/policy-engine/thumbgate-policy-engine-adapter.js +260 -0
  23. package/bench/observability-eval-suite.json +26 -0
  24. package/bench/thumbgate-bench.json +2 -2
  25. package/bin/cli.js +1456 -122
  26. package/bin/dashboard-cli.js +7 -0
  27. package/bin/postinstall.js +11 -27
  28. package/commands/dashboard.md +15 -0
  29. package/commands/thumbgate-dashboard.md +15 -0
  30. package/config/gate-classifier-routing.json +98 -0
  31. package/config/gate-templates.json +216 -0
  32. package/config/gates/claim-verification.json +12 -0
  33. package/config/gates/default.json +31 -2
  34. package/config/github-about.json +2 -2
  35. package/config/mcp-allowlists.json +23 -13
  36. package/config/merge-quality-checks.json +0 -1
  37. package/config/model-candidates.json +121 -6
  38. package/config/post-deploy-marketing-pages.json +80 -0
  39. package/config/tessl-tiles.json +1 -3
  40. package/openapi/openapi.yaml +12 -0
  41. package/package.json +225 -100
  42. package/public/about.html +162 -0
  43. package/public/agent-manager.html +179 -0
  44. package/public/agents-cost-savings.html +153 -0
  45. package/public/ai-malpractice-prevention.html +818 -0
  46. package/public/assets/brand/github-social-preview.png +0 -0
  47. package/public/assets/brand/thumbgate-icon-512.png +0 -0
  48. package/public/assets/brand/thumbgate-icon-pro-512.png +0 -0
  49. package/public/assets/brand/thumbgate-icon-team-512.png +0 -0
  50. package/public/assets/brand/thumbgate-logo-1200x360.png +0 -0
  51. package/public/assets/brand/thumbgate-logo-transparent.svg +28 -0
  52. package/public/assets/brand/thumbgate-mark-inline-v3.svg +18 -0
  53. package/public/assets/brand/thumbgate-mark-pro.svg +23 -0
  54. package/public/assets/brand/thumbgate-mark-team.svg +26 -0
  55. package/public/assets/brand/thumbgate-mark.svg +21 -0
  56. package/public/assets/brand/thumbgate-wordmark.svg +20 -0
  57. package/public/assets/claude-thumbgate-statusbar.svg +8 -0
  58. package/public/assets/codex-thumbgate-statusbar-test.svg +9 -0
  59. package/public/assets/legal-intake-control-flow.svg +66 -0
  60. package/public/blog.html +4 -4
  61. package/public/brand/thumbgate-mark.svg +19 -0
  62. package/public/brand/thumbgate-og.svg +16 -0
  63. package/public/chatgpt-app.html +330 -0
  64. package/public/codex-enterprise.html +123 -0
  65. package/public/codex-plugin.html +72 -20
  66. package/public/compare.html +31 -8
  67. package/public/dashboard.html +930 -166
  68. package/public/diagnostic.html +345 -0
  69. package/public/federal.html +2 -2
  70. package/public/guide.html +33 -13
  71. package/public/index.html +469 -111
  72. package/public/install.html +193 -0
  73. package/public/js/buyer-intent.js +672 -0
  74. package/public/learn.html +183 -18
  75. package/public/lessons.html +168 -10
  76. package/public/numbers.html +7 -7
  77. package/public/pricing.html +399 -0
  78. package/public/pro.html +34 -11
  79. package/scripts/action-receipts.js +324 -0
  80. package/scripts/activation-quickstart.js +187 -0
  81. package/scripts/agent-memory-lifecycle.js +211 -0
  82. package/scripts/agent-operations-planner.js +621 -0
  83. package/scripts/agent-readiness.js +20 -3
  84. package/scripts/agent-reward-model.js +53 -1
  85. package/scripts/ai-component-inventory.js +367 -0
  86. package/scripts/async-eval-observability.js +236 -0
  87. package/scripts/audit.js +65 -0
  88. package/scripts/auto-promote-gates.js +82 -10
  89. package/scripts/auto-wire-hooks.js +14 -0
  90. package/scripts/aws-blocks-guardrails.js +272 -0
  91. package/scripts/billing.js +93 -1
  92. package/scripts/bot-detection.js +61 -3
  93. package/scripts/build-metadata.js +50 -10
  94. package/scripts/classifier-routing.js +130 -0
  95. package/scripts/cli-feedback.js +4 -2
  96. package/scripts/cli-schema.js +97 -0
  97. package/scripts/cli-telemetry.js +6 -1
  98. package/scripts/commercial-offer.js +82 -2
  99. package/scripts/context-manager.js +74 -6
  100. package/scripts/dashboard-chat.js +332 -0
  101. package/scripts/dashboard.js +68 -2
  102. package/scripts/export-databricks-bundle.js +5 -1
  103. package/scripts/export-dpo-pairs.js +7 -2
  104. package/scripts/feedback-aggregate.js +281 -0
  105. package/scripts/feedback-loop.js +123 -1
  106. package/scripts/feedback-quality.js +87 -0
  107. package/scripts/feedback-sanitizer.js +105 -0
  108. package/scripts/filesystem-search.js +35 -10
  109. package/scripts/gate-stats.js +89 -0
  110. package/scripts/gates-engine.js +1176 -85
  111. package/scripts/gemini-embedding-policy.js +2 -1
  112. package/scripts/hook-runtime.js +20 -14
  113. package/scripts/hook-stop-anti-claim.js +301 -0
  114. package/scripts/hook-thumbgate-cache-updater.js +18 -2
  115. package/scripts/hybrid-feedback-context.js +142 -7
  116. package/scripts/install-shim.js +87 -0
  117. package/scripts/lesson-inference.js +8 -3
  118. package/scripts/lesson-search.js +17 -1
  119. package/scripts/license.js +10 -10
  120. package/scripts/llm-client.js +169 -4
  121. package/scripts/local-model-profile.js +15 -8
  122. package/scripts/mcp-config.js +7 -1
  123. package/scripts/mcp-oauth.js +293 -0
  124. package/scripts/memory-scope-readiness.js +159 -0
  125. package/scripts/meta-agent-loop.js +36 -0
  126. package/scripts/noop-detect.js +285 -0
  127. package/scripts/operational-integrity.js +39 -5
  128. package/scripts/oss-pr-opportunity-scout.js +35 -5
  129. package/scripts/parallel-workflow-orchestrator.js +293 -0
  130. package/scripts/plan-gate.js +243 -0
  131. package/scripts/plausible-domain-config.js +99 -0
  132. package/scripts/plausible-server-events.js +9 -6
  133. package/scripts/pro-local-dashboard.js +4 -4
  134. package/scripts/proxy-pointer-rag-guardrails.js +42 -1
  135. package/scripts/published-cli.js +0 -8
  136. package/scripts/qa-scenario-planner.js +136 -0
  137. package/scripts/rate-limiter.js +64 -13
  138. package/scripts/repeat-metric.js +137 -0
  139. package/scripts/secret-fixture-tokens.js +61 -0
  140. package/scripts/secret-redaction.js +166 -0
  141. package/scripts/secret-scanner.js +44 -5
  142. package/scripts/security-scanner.js +260 -10
  143. package/scripts/self-distill-agent.js +3 -1
  144. package/scripts/self-harness-optimizer.js +141 -0
  145. package/scripts/self-healing-check.js +193 -0
  146. package/scripts/self-protection.js +90 -0
  147. package/scripts/seo-gsd.js +916 -7
  148. package/scripts/silent-failure-cluster.js +531 -0
  149. package/scripts/statusline-cache-path.js +17 -2
  150. package/scripts/statusline-cache-read.js +57 -0
  151. package/scripts/statusline-local-stats.js +9 -1
  152. package/scripts/statusline-meta.js +28 -2
  153. package/scripts/statusline.sh +20 -4
  154. package/scripts/sync-telemetry-from-prod.js +374 -0
  155. package/scripts/telemetry-analytics.js +357 -0
  156. package/scripts/thompson-sampling.js +31 -10
  157. package/scripts/thumbgate-bench.js +16 -1
  158. package/scripts/thumbgate-search.js +85 -19
  159. package/scripts/tool-contract-validator.js +76 -0
  160. package/scripts/tool-registry.js +169 -1
  161. package/scripts/trajectory-scorer.js +63 -0
  162. package/scripts/vector-store.js +45 -0
  163. package/scripts/verify-marketing-pages-deployed.js +212 -0
  164. package/scripts/visitor-journey.js +172 -0
  165. package/scripts/workflow-sentinel.js +286 -53
  166. package/scripts/workspace-evolver.js +62 -2
  167. package/src/api/server.js +2683 -319
  168. package/.claude-plugin/marketplace.json +0 -85
  169. package/adapters/chatgpt/openapi.yaml +0 -1695
  170. package/scripts/bot-detector.js +0 -50
@@ -0,0 +1,193 @@
1
+ #!/usr/bin/env node
2
+ const fs = require('node:fs');
3
+ const os = require('node:os');
4
+ const path = require('node:path');
5
+ const { spawnSync } = require('node:child_process');
6
+ const { diagnoseFailure } = require('./failure-diagnostics');
7
+ const { appendDiagnosticRecord } = require('./feedback-loop');
8
+
9
+ const PROJECT_ROOT = path.join(__dirname, '..');
10
+ const DEFAULT_MAX_BUFFER_BYTES = 64 * 1024 * 1024;
11
+ const DEFAULT_TESTS_TIMEOUT_MS = Number.parseInt(
12
+ process.env.THUMBGATE_SELF_HEAL_TEST_TIMEOUT_MS || '',
13
+ 10,
14
+ ) || 60 * 60_000;
15
+
16
+ const DEFAULT_CHECKS = [
17
+ { name: 'budget_status', command: ['npm', 'run', 'budget:status'], timeoutMs: 60_000 },
18
+ { name: 'tests', command: ['npm', 'test'], timeoutMs: DEFAULT_TESTS_TIMEOUT_MS },
19
+ { name: 'prove_adapters', command: ['npm', 'run', 'prove:adapters'], timeoutMs: 10 * 60_000, useTempProofDir: true },
20
+ { name: 'prove_automation', command: ['npm', 'run', 'prove:automation'], timeoutMs: 10 * 60_000, useTempProofDir: true },
21
+ { name: 'prove_data_pipeline', command: ['npm', 'run', 'prove:data-pipeline'], timeoutMs: 10 * 60_000, useTempProofDir: true },
22
+ { name: 'prove_tessl', command: ['npm', 'run', 'prove:tessl'], timeoutMs: 10 * 60_000, useTempProofDir: true },
23
+ ];
24
+
25
+ function runCommand(command, {
26
+ cwd = PROJECT_ROOT,
27
+ timeoutMs = 5 * 60_000,
28
+ env = process.env,
29
+ maxBufferBytes = DEFAULT_MAX_BUFFER_BYTES,
30
+ } = {}) {
31
+ const [cmd, ...args] = command;
32
+ const started = Date.now();
33
+ const result = spawnSync(cmd, args, {
34
+ cwd,
35
+ env,
36
+ encoding: 'utf-8',
37
+ timeout: timeoutMs,
38
+ maxBuffer: maxBufferBytes,
39
+ shell: false,
40
+ });
41
+
42
+ const durationMs = Date.now() - started;
43
+ const status = Number.isInteger(result.status) ? result.status : 1;
44
+ return {
45
+ exitCode: status,
46
+ durationMs,
47
+ stdout: result.stdout || '',
48
+ stderr: result.stderr || '',
49
+ error: result.error ? result.error.message : null,
50
+ };
51
+ }
52
+
53
+ function createCheckEnvironment(check) {
54
+ const environment = { ...process.env };
55
+ let cleanup = null;
56
+
57
+ if (check.useTempProofDir) {
58
+ const proofDir = fs.mkdtempSync(path.join(os.tmpdir(), `thumbgate-${check.name}-`));
59
+ environment.THUMBGATE_PROOF_DIR = proofDir;
60
+ if (check.name === 'prove_automation') {
61
+ environment.THUMBGATE_AUTOMATION_PROOF_DIR = proofDir;
62
+ }
63
+ cleanup = () => {
64
+ fs.rmSync(proofDir, { recursive: true, force: true });
65
+ };
66
+ }
67
+
68
+ return { env: environment, cleanup };
69
+ }
70
+
71
+ function collectHealthReport({
72
+ checks = DEFAULT_CHECKS,
73
+ runner = runCommand,
74
+ cwd = PROJECT_ROOT,
75
+ persistDiagnostics = false,
76
+ } = {}) {
77
+ const startedAt = new Date();
78
+ const results = checks.map((check) => {
79
+ const { env, cleanup } = createCheckEnvironment(check);
80
+ let run;
81
+ try {
82
+ run = runner(check.command, { cwd, timeoutMs: check.timeoutMs, env });
83
+ } finally {
84
+ if (cleanup) {
85
+ cleanup();
86
+ }
87
+ }
88
+ const diagnosis = run.exitCode === 0
89
+ ? null
90
+ : diagnoseFailure({
91
+ step: check.name,
92
+ context: check.command.join(' '),
93
+ healthCheck: {
94
+ name: check.name,
95
+ exitCode: run.exitCode,
96
+ status: 'unhealthy',
97
+ outputTail: `${run.stdout}\n${run.stderr}`.trim().slice(-2000),
98
+ },
99
+ exitCode: run.exitCode,
100
+ error: run.error,
101
+ output: `${run.stdout}\n${run.stderr}`.trim(),
102
+ });
103
+ const persistedDiagnosis = persistDiagnostics && diagnosis
104
+ ? appendDiagnosticRecord({
105
+ source: 'self_heal_check',
106
+ step: check.name,
107
+ context: check.command.join(' '),
108
+ diagnosis,
109
+ metadata: {
110
+ command: check.command.join(' '),
111
+ },
112
+ })
113
+ : null;
114
+ return {
115
+ name: check.name,
116
+ command: check.command.join(' '),
117
+ status: run.exitCode === 0 ? 'healthy' : 'unhealthy',
118
+ exitCode: run.exitCode,
119
+ durationMs: run.durationMs,
120
+ error: run.error,
121
+ outputTail: `${run.stdout}\n${run.stderr}`.trim().slice(-2000),
122
+ diagnosis,
123
+ persistedDiagnosis,
124
+ };
125
+ });
126
+
127
+ const healthyCount = results.filter((x) => x.status === 'healthy').length;
128
+ const unhealthyCount = results.length - healthyCount;
129
+
130
+ return {
131
+ generatedAt: startedAt.toISOString(),
132
+ durationMs: Date.now() - startedAt.getTime(),
133
+ overall_status: unhealthyCount === 0 ? 'healthy' : 'unhealthy',
134
+ summary: {
135
+ total: results.length,
136
+ healthy: healthyCount,
137
+ unhealthy: unhealthyCount,
138
+ },
139
+ checks: results,
140
+ };
141
+ }
142
+
143
+ function reportToText(report) {
144
+ const lines = [];
145
+ lines.push(`Self-Healing Health Check @ ${report.generatedAt}`);
146
+ lines.push(`Overall: ${report.overall_status.toUpperCase()}`);
147
+ lines.push(`Checks: ${report.summary.healthy}/${report.summary.total} healthy`);
148
+ lines.push('');
149
+
150
+ report.checks.forEach((check) => {
151
+ const icon = check.status === 'healthy' ? '✅' : '❌';
152
+ lines.push(`${icon} ${check.name} (${check.durationMs}ms)`);
153
+ if (check.status !== 'healthy') {
154
+ lines.push(` command: ${check.command}`);
155
+ if (check.error) lines.push(` error: ${check.error}`);
156
+ if (check.diagnosis && check.diagnosis.rootCauseCategory) {
157
+ lines.push(` diagnosis: ${check.diagnosis.rootCauseCategory}`);
158
+ }
159
+ }
160
+ });
161
+
162
+ return `${lines.join('\n')}\n`;
163
+ }
164
+
165
+ function runCli() {
166
+ const args = new Set(process.argv.slice(2));
167
+ const emitJson = args.has('--json');
168
+ const noFail = args.has('--no-fail');
169
+ const report = collectHealthReport({ persistDiagnostics: true });
170
+
171
+ if (emitJson) {
172
+ console.log(JSON.stringify(report, null, 2));
173
+ } else {
174
+ process.stdout.write(reportToText(report));
175
+ }
176
+
177
+ if (!noFail && report.overall_status !== 'healthy') {
178
+ process.exit(1);
179
+ }
180
+ }
181
+
182
+ module.exports = {
183
+ DEFAULT_CHECKS,
184
+ DEFAULT_TESTS_TIMEOUT_MS,
185
+ DEFAULT_MAX_BUFFER_BYTES,
186
+ runCommand,
187
+ collectHealthReport,
188
+ reportToText,
189
+ };
190
+
191
+ if (require.main === module) {
192
+ runCli();
193
+ }
@@ -0,0 +1,90 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * self-protection.js — guard the files that configure ThumbGate itself.
5
+ *
6
+ * Added 2026-07-08 after Andy Martin's review: in the shipped `gate-check`
7
+ * path, editing ThumbGate's own hook wiring / gate config was ALLOWED by
8
+ * default (warn-by-default posture only denies under strict enforcement), so
9
+ * an agent could disable the firewall before continuing and the surfaced
10
+ * verdict was a clean ALLOW.
11
+ *
12
+ * This module is the single source of truth for "is this edit touching the
13
+ * firewall's own kill-switches", used by BOTH the shipped `npx thumbgate
14
+ * gate-check` entrypoint and this repo's dogfood PreToolUse hook.
15
+ *
16
+ * Posture threads three constraints:
17
+ * * Andy's ask: don't let the agent quietly rewrite/disable the gate.
18
+ * * CEO warn-by-default (2026-06-04): never hard-block legitimate work.
19
+ * * Self-lockout lesson (2026-07-07): a PreToolUse hook must NEVER deny the
20
+ * tools needed to repair its own config, or the agent is bricked.
21
+ *
22
+ * Resolution:
23
+ * default -> WARN (surfaced + logged, never silent)
24
+ * THUMBGATE_STRICT_ENFORCEMENT=1 -> BLOCK
25
+ * THUMBGATE_ALLOW_SELF_EDIT=1 -> full opt-out (preserves the repair path)
26
+ */
27
+
28
+ const SELF_GOVERNANCE_PATH_PATTERNS = [
29
+ /(?:^|\/)\.claude\/settings(?:\.local)?\.json$/i, // hook wiring / can disable ThumbGate
30
+ /(?:^|\/)\.codex\/config\.toml$/i,
31
+ /(?:^|\/)scripts\/hook-[^/]+\.(?:js|sh)$/i, // the hook scripts themselves
32
+ /(?:^|\/)config\/gates\//i, // gate definitions
33
+ /(?:^|\/)config\/enforcement\.json$/i, // enforcement policy
34
+ /(?:^|\/)config\/mcp-allowlists\.json$/i, // MCP policy surface
35
+ ];
36
+
37
+ const EDIT_LIKE_TOOLS = new Set(['Edit', 'Write', 'MultiEdit']);
38
+
39
+ function isTrueEnv(value) {
40
+ if (value === undefined || value === null) return false;
41
+ const v = String(value).trim().toLowerCase();
42
+ return v === '1' || v === 'true' || v === 'yes' || v === 'on';
43
+ }
44
+
45
+ /**
46
+ * Returns the matched governance file path, or null. Accepts both camelCase
47
+ * (`tool_name`/`tool_input`) and the already-normalized shapes callers use.
48
+ */
49
+ function selfProtectionTarget(toolName, toolInput) {
50
+ if (!EDIT_LIKE_TOOLS.has(toolName)) return null;
51
+ const filePath = String((toolInput && (toolInput.file_path || toolInput.filePath)) || '');
52
+ if (!filePath) return null;
53
+ return SELF_GOVERNANCE_PATH_PATTERNS.some((re) => re.test(filePath)) ? filePath : null;
54
+ }
55
+
56
+ /**
57
+ * Evaluate the self-protection posture for a tool call.
58
+ * @returns {{action:'block'|'warn', target:string, message:string}|null}
59
+ */
60
+ function evaluateSelfProtection(toolName, toolInput, env = process.env) {
61
+ const target = selfProtectionTarget(toolName, toolInput);
62
+ if (!target) return null;
63
+ // Escape hatch: an operator repairing the gate opts out explicitly. Honors the
64
+ // self-lockout lesson — the repair path is never denied.
65
+ if (isTrueEnv(env.THUMBGATE_ALLOW_SELF_EDIT)) return null;
66
+ if (isTrueEnv(env.THUMBGATE_STRICT_ENFORCEMENT)) {
67
+ return {
68
+ action: 'block',
69
+ target,
70
+ message:
71
+ `ThumbGate self-protection: blocked ${toolName} to its own governance file "${target}". `
72
+ + `Editing the firewall's own hook wiring / gate config while strict enforcement is on is denied. `
73
+ + `Set THUMBGATE_ALLOW_SELF_EDIT=1 to make an intentional repair.`,
74
+ };
75
+ }
76
+ return {
77
+ action: 'warn',
78
+ target,
79
+ message:
80
+ `⚠️ ThumbGate self-protection: this ${toolName} targets a governance file that configures the firewall itself `
81
+ + `("${target}"). It is being ALLOWED and LOGGED (warn-by-default). An agent editing this could weaken or disable `
82
+ + `its own guardrails — confirm this is intentional. Set THUMBGATE_STRICT_ENFORCEMENT=1 to hard-block such edits.`,
83
+ };
84
+ }
85
+
86
+ module.exports = {
87
+ SELF_GOVERNANCE_PATH_PATTERNS,
88
+ selfProtectionTarget,
89
+ evaluateSelfProtection,
90
+ };