thumbgate 0.9.14 → 1.1.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 +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.well-known/mcp/server-card.json +1 -1
- package/README.md +1 -0
- package/adapters/README.md +1 -1
- package/adapters/chatgpt/openapi.yaml +105 -0
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/codex/config.toml +2 -2
- package/adapters/forge/forge.yaml +28 -0
- package/adapters/mcp/server-stdio.js +41 -1
- package/adapters/opencode/opencode.json +1 -1
- package/bin/cli.js +18 -3
- package/config/mcp-allowlists.json +11 -0
- package/openapi/openapi.yaml +105 -0
- package/package.json +7 -5
- package/plugins/amp-skill/INSTALL.md +3 -4
- package/plugins/amp-skill/SKILL.md +0 -1
- package/plugins/claude-codex-bridge/.claude-plugin/plugin.json +1 -1
- package/plugins/claude-codex-bridge/.mcp.json +1 -1
- package/plugins/claude-skill/INSTALL.md +1 -2
- package/plugins/codex-profile/.codex-plugin/plugin.json +1 -1
- package/plugins/codex-profile/.mcp.json +1 -1
- package/plugins/codex-profile/INSTALL.md +1 -1
- package/plugins/codex-profile/README.md +1 -1
- package/plugins/cursor-marketplace/.cursor-plugin/plugin.json +1 -1
- package/plugins/opencode-profile/INSTALL.md +1 -1
- package/public/blog.html +1 -0
- package/public/dashboard.html +1 -1
- package/public/guide.html +1 -1
- package/public/index.html +8 -4
- package/public/learn/agent-harness-pattern.html +1 -1
- package/public/learn/ai-agent-persistent-memory.html +1 -1
- package/public/learn/mcp-pre-action-gates-explained.html +1 -1
- package/public/learn/stop-ai-agent-force-push.html +1 -1
- package/public/learn/vibe-coding-safety-net.html +1 -1
- package/public/learn.html +1 -1
- package/public/lessons.html +1 -1
- package/public/pro.html +1 -1
- package/scripts/__pycache__/train_from_feedback.cpython-312.pyc +0 -0
- package/scripts/agent-security-hardening.js +4 -4
- package/scripts/async-job-runner.js +84 -24
- package/scripts/auto-wire-hooks.js +59 -1
- package/scripts/context-manager.js +330 -0
- package/scripts/dashboard.js +1 -1
- package/scripts/distribution-surfaces.js +12 -0
- package/scripts/ensure-repo-bootstrap.js +15 -14
- package/scripts/export-hf-dataset.js +293 -0
- package/scripts/gates-engine.js +96 -10
- package/scripts/hook-auto-capture.sh +1 -1
- package/scripts/hosted-job-launcher.js +260 -0
- package/scripts/managed-dpo-export.js +91 -0
- package/scripts/obsidian-export.js +0 -1
- package/scripts/operational-integrity.js +50 -7
- package/scripts/prove-lancedb.js +62 -4
- package/scripts/publish-decision.js +16 -0
- package/scripts/self-healing-check.js +6 -1
- package/scripts/social-analytics/load-env.js +33 -2
- package/scripts/social-analytics/store.js +200 -2
- package/scripts/sync-version.js +18 -11
- package/scripts/tool-registry.js +48 -0
- package/scripts/train_from_feedback.py +0 -4
- package/scripts/workflow-sentinel.js +793 -0
- package/src/api/server.js +205 -27
- /package/scripts/{rlhf_session_start.sh → thumbgate_session_start.sh} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thumbgate",
|
|
3
3
|
"description": "Pre-action gates that block AI coding agents from repeating known mistakes. Captures feedback, auto-promotes failures into prevention rules, and enforces them via PreToolUse hooks.",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "1.1.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Igor Ganapolsky"
|
|
7
7
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thumbgate",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "ThumbGate — 👍👎 feedback that teaches your AI agent. Thumbs down a mistake, it never happens again.",
|
|
5
5
|
"homepage": "https://github.com/IgorGanapolsky/thumbgate",
|
|
6
6
|
"transport": "stdio",
|
package/README.md
CHANGED
|
@@ -169,6 +169,7 @@ It does not update model weights. It's context engineering — enforcement that
|
|
|
169
169
|
## Docs
|
|
170
170
|
|
|
171
171
|
- [Commercial Truth](docs/COMMERCIAL_TRUTH.md) — pricing, claims, what we don't say
|
|
172
|
+
- [SemVer Policy](docs/SEMVER_POLICY.md) — stable vs prerelease channel rules
|
|
172
173
|
- [Verification Evidence](docs/VERIFICATION_EVIDENCE.md) — proof artifacts
|
|
173
174
|
- [WORKFLOW.md](WORKFLOW.md) — agent-run contract (scope, hard stops, proof commands)
|
|
174
175
|
- [ready-for-agent issue template](.github/ISSUE_TEMPLATE/ready-for-agent.yml) — intake for agent tasks
|
package/adapters/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
- `chatgpt/openapi.yaml`: import into GPT Actions.
|
|
4
4
|
- `gemini/function-declarations.json`: Gemini function-calling definitions.
|
|
5
5
|
- `mcp/server-stdio.js`: underlying local MCP stdio server implementation.
|
|
6
|
-
- `claude/.mcp.json`: example Claude Code MCP config using `npx --yes --package thumbgate@
|
|
6
|
+
- `claude/.mcp.json`: example Claude Code MCP config using `npx --yes --package thumbgate@1.1.0 thumbgate serve`.
|
|
7
7
|
- `codex/config.toml`: example Codex MCP profile section using the same version-pinned portable launcher.
|
|
8
8
|
- `amp/skills/thumbgate-feedback/SKILL.md`: Amp skill template.
|
|
9
9
|
- `opencode/opencode.json`: portable OpenCode MCP profile using the same version-pinned portable launcher.
|
|
@@ -1101,11 +1101,116 @@ paths:
|
|
|
1101
1101
|
type: string
|
|
1102
1102
|
outputPath:
|
|
1103
1103
|
type: string
|
|
1104
|
+
async:
|
|
1105
|
+
type: boolean
|
|
1106
|
+
mode:
|
|
1107
|
+
type: string
|
|
1108
|
+
enum: [sync, async]
|
|
1109
|
+
jobId:
|
|
1110
|
+
type: string
|
|
1104
1111
|
responses:
|
|
1105
1112
|
'200':
|
|
1106
1113
|
description: DPO export completed
|
|
1114
|
+
'202':
|
|
1115
|
+
description: DPO export accepted as a hosted background job
|
|
1116
|
+
'401':
|
|
1117
|
+
description: Unauthorized
|
|
1118
|
+
/v1/jobs:
|
|
1119
|
+
get:
|
|
1120
|
+
operationId: listHostedJobs
|
|
1121
|
+
parameters:
|
|
1122
|
+
- in: query
|
|
1123
|
+
name: limit
|
|
1124
|
+
schema:
|
|
1125
|
+
type: integer
|
|
1126
|
+
default: 20
|
|
1127
|
+
- in: query
|
|
1128
|
+
name: status
|
|
1129
|
+
schema:
|
|
1130
|
+
type: string
|
|
1131
|
+
description: Optional comma-separated list of job statuses to filter.
|
|
1132
|
+
responses:
|
|
1133
|
+
'200':
|
|
1134
|
+
description: Hosted job states
|
|
1135
|
+
'401':
|
|
1136
|
+
description: Unauthorized
|
|
1137
|
+
/v1/jobs/harness:
|
|
1138
|
+
post:
|
|
1139
|
+
operationId: launchHostedHarness
|
|
1140
|
+
requestBody:
|
|
1141
|
+
required: true
|
|
1142
|
+
content:
|
|
1143
|
+
application/json:
|
|
1144
|
+
schema:
|
|
1145
|
+
type: object
|
|
1146
|
+
required: [harness]
|
|
1147
|
+
properties:
|
|
1148
|
+
harness:
|
|
1149
|
+
type: string
|
|
1150
|
+
harnessId:
|
|
1151
|
+
type: string
|
|
1152
|
+
jobId:
|
|
1153
|
+
type: string
|
|
1154
|
+
skill:
|
|
1155
|
+
type: string
|
|
1156
|
+
partnerProfile:
|
|
1157
|
+
type: string
|
|
1158
|
+
autoImprove:
|
|
1159
|
+
type: boolean
|
|
1160
|
+
inputs:
|
|
1161
|
+
type: object
|
|
1162
|
+
responses:
|
|
1163
|
+
'202':
|
|
1164
|
+
description: Hosted harness accepted
|
|
1165
|
+
'401':
|
|
1166
|
+
description: Unauthorized
|
|
1167
|
+
/v1/jobs/{jobId}:
|
|
1168
|
+
get:
|
|
1169
|
+
operationId: getHostedJob
|
|
1170
|
+
parameters:
|
|
1171
|
+
- in: path
|
|
1172
|
+
name: jobId
|
|
1173
|
+
required: true
|
|
1174
|
+
schema:
|
|
1175
|
+
type: string
|
|
1176
|
+
responses:
|
|
1177
|
+
'200':
|
|
1178
|
+
description: Hosted job state
|
|
1179
|
+
'401':
|
|
1180
|
+
description: Unauthorized
|
|
1181
|
+
'404':
|
|
1182
|
+
description: Job not found
|
|
1183
|
+
/v1/jobs/{jobId}/control:
|
|
1184
|
+
post:
|
|
1185
|
+
operationId: controlHostedJob
|
|
1186
|
+
parameters:
|
|
1187
|
+
- in: path
|
|
1188
|
+
name: jobId
|
|
1189
|
+
required: true
|
|
1190
|
+
schema:
|
|
1191
|
+
type: string
|
|
1192
|
+
requestBody:
|
|
1193
|
+
required: true
|
|
1194
|
+
content:
|
|
1195
|
+
application/json:
|
|
1196
|
+
schema:
|
|
1197
|
+
type: object
|
|
1198
|
+
required: [action]
|
|
1199
|
+
properties:
|
|
1200
|
+
action:
|
|
1201
|
+
type: string
|
|
1202
|
+
enum: [pause, cancel, resume]
|
|
1203
|
+
metadata:
|
|
1204
|
+
type: object
|
|
1205
|
+
responses:
|
|
1206
|
+
'202':
|
|
1207
|
+
description: Hosted job control accepted
|
|
1107
1208
|
'401':
|
|
1108
1209
|
description: Unauthorized
|
|
1210
|
+
'404':
|
|
1211
|
+
description: Job not found
|
|
1212
|
+
'409':
|
|
1213
|
+
description: Job cannot accept the requested control action
|
|
1109
1214
|
/v1/analytics/databricks/export:
|
|
1110
1215
|
post:
|
|
1111
1216
|
operationId: exportDatabricksBundle
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
"mcpServers": {
|
|
3
3
|
"thumbgate": {
|
|
4
4
|
"command": "npx",
|
|
5
|
-
"args": ["--yes", "--package", "thumbgate@
|
|
5
|
+
"args": ["--yes", "--package", "thumbgate@1.1.0", "thumbgate", "serve"]
|
|
6
6
|
}
|
|
7
7
|
},
|
|
8
8
|
"hooks": {
|
|
9
9
|
"preToolUse": {
|
|
10
10
|
"command": "npx",
|
|
11
|
-
"args": ["--yes", "--package", "thumbgate@
|
|
11
|
+
"args": ["--yes", "--package", "thumbgate@1.1.0", "thumbgate", "gate-check"]
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Codex MCP profile (copy into ~/.codex/config.toml or merge section)
|
|
2
2
|
[mcp_servers.thumbgate]
|
|
3
3
|
command = "npx"
|
|
4
|
-
args = ["--yes", "--package", "thumbgate@
|
|
4
|
+
args = ["--yes", "--package", "thumbgate@1.1.0", "thumbgate", "serve"]
|
|
5
5
|
|
|
6
6
|
# Hard PreToolUse hook for Codex
|
|
7
7
|
[hooks.pre_tool_use]
|
|
8
8
|
command = "npx"
|
|
9
|
-
args = ["--yes", "--package", "thumbgate@
|
|
9
|
+
args = ["--yes", "--package", "thumbgate@1.1.0", "thumbgate", "gate-check"]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# ForgeCode ThumbGate integration
|
|
2
|
+
# Copy into your project's forge.yaml or merge with existing config.
|
|
3
|
+
#
|
|
4
|
+
# ForgeCode (https://github.com/antinomyhq/forgecode) supports custom skills
|
|
5
|
+
# that ThumbGate uses to gate tool calls before execution.
|
|
6
|
+
|
|
7
|
+
version: "1"
|
|
8
|
+
|
|
9
|
+
skills:
|
|
10
|
+
thumbgate-gate-check:
|
|
11
|
+
description: "ThumbGate PreToolUse gate — blocks known-bad tool calls"
|
|
12
|
+
command: "npx --yes --package thumbgate@0.9.13 thumbgate gate-check"
|
|
13
|
+
trigger: pre_tool_use
|
|
14
|
+
|
|
15
|
+
thumbgate-feedback:
|
|
16
|
+
description: "ThumbGate feedback capture — logs user prompt context"
|
|
17
|
+
command: "npx --yes --package thumbgate@0.9.13 thumbgate hook-auto-capture"
|
|
18
|
+
trigger: user_prompt
|
|
19
|
+
|
|
20
|
+
mcp:
|
|
21
|
+
thumbgate:
|
|
22
|
+
command: "npx"
|
|
23
|
+
args:
|
|
24
|
+
- "--yes"
|
|
25
|
+
- "--package"
|
|
26
|
+
- "thumbgate@0.9.13"
|
|
27
|
+
- "thumbgate"
|
|
28
|
+
- "serve"
|
|
@@ -55,6 +55,9 @@ const {
|
|
|
55
55
|
const {
|
|
56
56
|
evaluateOperationalIntegrity,
|
|
57
57
|
} = require('../../scripts/operational-integrity');
|
|
58
|
+
const {
|
|
59
|
+
evaluateWorkflowSentinel,
|
|
60
|
+
} = require('../../scripts/workflow-sentinel');
|
|
58
61
|
const { diagnoseFailure } = require('../../scripts/failure-diagnostics');
|
|
59
62
|
const {
|
|
60
63
|
analyzeCodeGraphImpact,
|
|
@@ -90,6 +93,11 @@ const {
|
|
|
90
93
|
const { TOOLS } = require('../../scripts/tool-registry');
|
|
91
94
|
const { reflect: reflectOnFeedback } = require('../../scripts/reflector-agent');
|
|
92
95
|
const { submitProductIssue } = require('../../scripts/product-feedback');
|
|
96
|
+
const {
|
|
97
|
+
assembleUnifiedContext,
|
|
98
|
+
formatUnifiedContext,
|
|
99
|
+
} = require('../../scripts/context-manager');
|
|
100
|
+
const { exportHfDataset } = require('../../scripts/export-hf-dataset');
|
|
93
101
|
|
|
94
102
|
const PRO_CHECKOUT_URL = 'https://thumbgate-production.up.railway.app/checkout/pro';
|
|
95
103
|
|
|
@@ -111,7 +119,7 @@ const {
|
|
|
111
119
|
finalizeSession: finalizeFeedbackSession,
|
|
112
120
|
} = require('../../scripts/feedback-session');
|
|
113
121
|
|
|
114
|
-
const SERVER_INFO = { name: 'thumbgate-mcp', version: '
|
|
122
|
+
const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.1.0' };
|
|
115
123
|
const COMMERCE_CATEGORIES = [
|
|
116
124
|
'product_recommendation',
|
|
117
125
|
'brand_compliance',
|
|
@@ -486,6 +494,14 @@ async function callToolInner(name, args) {
|
|
|
486
494
|
case 'export_dpo_pairs':
|
|
487
495
|
enforceLimit('export_dpo');
|
|
488
496
|
return buildExportDpoResponse(args);
|
|
497
|
+
case 'export_hf_dataset': {
|
|
498
|
+
enforceLimit('export_dpo');
|
|
499
|
+
const outputDir = args.outputDir ? resolveSafePath(args.outputDir) : undefined;
|
|
500
|
+
return toTextResult(exportHfDataset({
|
|
501
|
+
outputDir,
|
|
502
|
+
includeProvenance: args.includeProvenance !== false,
|
|
503
|
+
}));
|
|
504
|
+
}
|
|
489
505
|
case 'export_databricks_bundle': {
|
|
490
506
|
enforceLimit('export_databricks');
|
|
491
507
|
const outputPath = args.outputPath ? resolveSafePath(args.outputPath) : undefined;
|
|
@@ -508,6 +524,16 @@ async function callToolInner(name, args) {
|
|
|
508
524
|
});
|
|
509
525
|
case 'recall':
|
|
510
526
|
return buildRecallResponse(args);
|
|
527
|
+
case 'unified_context': {
|
|
528
|
+
const ctx = assembleUnifiedContext({
|
|
529
|
+
query: args.query || '',
|
|
530
|
+
toolName: args.toolName,
|
|
531
|
+
toolInput: args.toolInput,
|
|
532
|
+
agentType: args.agentType,
|
|
533
|
+
repoPath: args.repoPath,
|
|
534
|
+
});
|
|
535
|
+
return toTextResult(formatUnifiedContext(ctx));
|
|
536
|
+
}
|
|
511
537
|
case 'satisfy_gate': {
|
|
512
538
|
if (!args.gate) {
|
|
513
539
|
throw new Error('gate is required');
|
|
@@ -589,6 +615,20 @@ async function callToolInner(name, args) {
|
|
|
589
615
|
requireVersionNotBehindBase: args.requireVersionNotBehindBase === true,
|
|
590
616
|
branchGovernance: getBranchGovernanceState(),
|
|
591
617
|
}));
|
|
618
|
+
case 'workflow_sentinel':
|
|
619
|
+
return toTextResult(evaluateWorkflowSentinel(args.toolName, {
|
|
620
|
+
command: args.command,
|
|
621
|
+
path: args.filePath,
|
|
622
|
+
changedFiles: Array.isArray(args.changedFiles) ? args.changedFiles : [],
|
|
623
|
+
repoPath: args.repoPath,
|
|
624
|
+
baseBranch: args.baseBranch,
|
|
625
|
+
}, {
|
|
626
|
+
repoPath: args.repoPath,
|
|
627
|
+
baseBranch: args.baseBranch,
|
|
628
|
+
affectedFiles: Array.isArray(args.changedFiles) ? args.changedFiles : undefined,
|
|
629
|
+
requirePrForReleaseSensitive: args.requirePrForReleaseSensitive === true,
|
|
630
|
+
requireVersionNotBehindBase: args.requireVersionNotBehindBase === true,
|
|
631
|
+
}));
|
|
592
632
|
case 'register_claim_gate':
|
|
593
633
|
return toTextResult(registerClaimGate(args.claimPattern, args.requiredActions, args.message));
|
|
594
634
|
case 'gate_stats':
|
package/bin/cli.js
CHANGED
|
@@ -442,6 +442,19 @@ function setupCursor() {
|
|
|
442
442
|
return mergeMcpJson(path.join(CWD, '.cursor', 'mcp.json'), 'Cursor', 'project');
|
|
443
443
|
}
|
|
444
444
|
|
|
445
|
+
function setupForge() {
|
|
446
|
+
const destPath = path.join(CWD, 'forge.yaml');
|
|
447
|
+
if (fs.existsSync(destPath)) {
|
|
448
|
+
// Don't overwrite existing forge.yaml — user may have custom config
|
|
449
|
+
return false;
|
|
450
|
+
}
|
|
451
|
+
const srcPath = path.join(PKG_ROOT, 'adapters', 'forge', 'forge.yaml');
|
|
452
|
+
if (!fs.existsSync(srcPath)) return false;
|
|
453
|
+
fs.copyFileSync(srcPath, destPath);
|
|
454
|
+
console.log(' ForgeCode: installed forge.yaml with ThumbGate skills');
|
|
455
|
+
return true;
|
|
456
|
+
}
|
|
457
|
+
|
|
445
458
|
function init() {
|
|
446
459
|
const args = parseArgs(process.argv.slice(3));
|
|
447
460
|
|
|
@@ -513,6 +526,7 @@ function init() {
|
|
|
513
526
|
{ name: 'Gemini', detect: [() => whichExists('gemini'), () => fs.existsSync(path.join(HOME, '.gemini'))], setup: setupGemini },
|
|
514
527
|
{ name: 'Amp', detect: [() => whichExists('amp'), () => fs.existsSync(path.join(HOME, '.amp'))], setup: setupAmp },
|
|
515
528
|
{ name: 'Cursor', detect: [() => fs.existsSync(path.join(HOME, '.cursor', 'mcp.json')), () => fs.existsSync(path.join(CWD, '.cursor'))], setup: setupCursor },
|
|
529
|
+
{ name: 'ForgeCode', detect: [() => whichExists('forge'), () => fs.existsSync(path.join(CWD, 'forge.yaml'))], setup: setupForge },
|
|
516
530
|
];
|
|
517
531
|
|
|
518
532
|
for (const p of platforms) {
|
|
@@ -1189,7 +1203,8 @@ function install() {
|
|
|
1189
1203
|
setupCodex(),
|
|
1190
1204
|
setupGemini(),
|
|
1191
1205
|
setupCursor(),
|
|
1192
|
-
setupAmp()
|
|
1206
|
+
setupAmp(),
|
|
1207
|
+
setupForge()
|
|
1193
1208
|
];
|
|
1194
1209
|
const success = results.some(r => r === true);
|
|
1195
1210
|
if (success) {
|
|
@@ -1320,11 +1335,11 @@ function help() {
|
|
|
1320
1335
|
console.log('');
|
|
1321
1336
|
console.log('Commands:');
|
|
1322
1337
|
console.log(' init Scaffold .thumbgate/ config + MCP server in current project');
|
|
1323
|
-
console.log(' --agent=NAME Wire PreToolUse hooks for agent (claude-code|codex|gemini)');
|
|
1338
|
+
console.log(' --agent=NAME Wire PreToolUse hooks for agent (claude-code|codex|gemini|forge)');
|
|
1324
1339
|
console.log(' --wire-hooks Wire hooks only (auto-detect agent, skip scaffolding)');
|
|
1325
1340
|
console.log(' --dry-run Preview hook changes without writing');
|
|
1326
1341
|
console.log(' install-mcp Install ThumbGate MCP server into Claude Code settings (--project for local)');
|
|
1327
|
-
console.log(' serve Start MCP server (stdio) — for claude/codex/gemini mcp add');
|
|
1342
|
+
console.log(' serve Start MCP server (stdio) — for claude/codex/gemini/forge mcp add');
|
|
1328
1343
|
console.log(' gate-check Internal: evaluate a PreToolUse payload from stdin');
|
|
1329
1344
|
console.log(' cache-update Internal: refresh the Claude statusline cache from stdin');
|
|
1330
1345
|
console.log(' statusline-render Internal: render the ThumbGate Claude status line');
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
"profiles": {
|
|
4
4
|
"default": [
|
|
5
5
|
"recall",
|
|
6
|
+
"unified_context",
|
|
6
7
|
"capture_feedback",
|
|
7
8
|
"open_feedback_session",
|
|
8
9
|
"append_feedback_context",
|
|
@@ -21,6 +22,7 @@
|
|
|
21
22
|
"bootstrap_internal_agent",
|
|
22
23
|
"prevention_rules",
|
|
23
24
|
"export_dpo_pairs",
|
|
25
|
+
"export_hf_dataset",
|
|
24
26
|
"export_databricks_bundle",
|
|
25
27
|
"construct_context_pack",
|
|
26
28
|
"evaluate_context_pack",
|
|
@@ -36,6 +38,7 @@
|
|
|
36
38
|
"track_action",
|
|
37
39
|
"verify_claim",
|
|
38
40
|
"check_operational_integrity",
|
|
41
|
+
"workflow_sentinel",
|
|
39
42
|
"register_claim_gate",
|
|
40
43
|
"gate_stats",
|
|
41
44
|
"dashboard",
|
|
@@ -56,6 +59,7 @@
|
|
|
56
59
|
"append_feedback_context",
|
|
57
60
|
"finalize_feedback_session",
|
|
58
61
|
"recall",
|
|
62
|
+
"unified_context",
|
|
59
63
|
"search_lessons",
|
|
60
64
|
"retrieve_lessons",
|
|
61
65
|
"search_thumbgate",
|
|
@@ -69,6 +73,7 @@
|
|
|
69
73
|
"track_action",
|
|
70
74
|
"verify_claim",
|
|
71
75
|
"check_operational_integrity",
|
|
76
|
+
"workflow_sentinel",
|
|
72
77
|
"feedback_stats",
|
|
73
78
|
"feedback_summary",
|
|
74
79
|
"estimate_uncertainty",
|
|
@@ -88,12 +93,14 @@
|
|
|
88
93
|
"track_action",
|
|
89
94
|
"verify_claim",
|
|
90
95
|
"check_operational_integrity",
|
|
96
|
+
"workflow_sentinel",
|
|
91
97
|
"prevention_rules",
|
|
92
98
|
"feedback_stats",
|
|
93
99
|
"feedback_summary"
|
|
94
100
|
],
|
|
95
101
|
"readonly": [
|
|
96
102
|
"recall",
|
|
103
|
+
"unified_context",
|
|
97
104
|
"feedback_summary",
|
|
98
105
|
"search_lessons",
|
|
99
106
|
"retrieve_lessons",
|
|
@@ -110,6 +117,7 @@
|
|
|
110
117
|
"get_branch_governance",
|
|
111
118
|
"verify_claim",
|
|
112
119
|
"check_operational_integrity",
|
|
120
|
+
"workflow_sentinel",
|
|
113
121
|
"gate_stats",
|
|
114
122
|
"dashboard",
|
|
115
123
|
"settings_status",
|
|
@@ -120,6 +128,7 @@
|
|
|
120
128
|
],
|
|
121
129
|
"dispatch": [
|
|
122
130
|
"recall",
|
|
131
|
+
"unified_context",
|
|
123
132
|
"feedback_summary",
|
|
124
133
|
"search_lessons",
|
|
125
134
|
"retrieve_lessons",
|
|
@@ -135,6 +144,7 @@
|
|
|
135
144
|
"get_branch_governance",
|
|
136
145
|
"verify_claim",
|
|
137
146
|
"check_operational_integrity",
|
|
147
|
+
"workflow_sentinel",
|
|
138
148
|
"gate_stats",
|
|
139
149
|
"dashboard",
|
|
140
150
|
"settings_status",
|
|
@@ -156,6 +166,7 @@
|
|
|
156
166
|
"get_branch_governance",
|
|
157
167
|
"verify_claim",
|
|
158
168
|
"check_operational_integrity",
|
|
169
|
+
"workflow_sentinel",
|
|
159
170
|
"settings_status"
|
|
160
171
|
]
|
|
161
172
|
}
|
package/openapi/openapi.yaml
CHANGED
|
@@ -1101,11 +1101,116 @@ paths:
|
|
|
1101
1101
|
type: string
|
|
1102
1102
|
outputPath:
|
|
1103
1103
|
type: string
|
|
1104
|
+
async:
|
|
1105
|
+
type: boolean
|
|
1106
|
+
mode:
|
|
1107
|
+
type: string
|
|
1108
|
+
enum: [sync, async]
|
|
1109
|
+
jobId:
|
|
1110
|
+
type: string
|
|
1104
1111
|
responses:
|
|
1105
1112
|
'200':
|
|
1106
1113
|
description: DPO export completed
|
|
1114
|
+
'202':
|
|
1115
|
+
description: DPO export accepted as a hosted background job
|
|
1116
|
+
'401':
|
|
1117
|
+
description: Unauthorized
|
|
1118
|
+
/v1/jobs:
|
|
1119
|
+
get:
|
|
1120
|
+
operationId: listHostedJobs
|
|
1121
|
+
parameters:
|
|
1122
|
+
- in: query
|
|
1123
|
+
name: limit
|
|
1124
|
+
schema:
|
|
1125
|
+
type: integer
|
|
1126
|
+
default: 20
|
|
1127
|
+
- in: query
|
|
1128
|
+
name: status
|
|
1129
|
+
schema:
|
|
1130
|
+
type: string
|
|
1131
|
+
description: Optional comma-separated list of job statuses to filter.
|
|
1132
|
+
responses:
|
|
1133
|
+
'200':
|
|
1134
|
+
description: Hosted job states
|
|
1135
|
+
'401':
|
|
1136
|
+
description: Unauthorized
|
|
1137
|
+
/v1/jobs/harness:
|
|
1138
|
+
post:
|
|
1139
|
+
operationId: launchHostedHarness
|
|
1140
|
+
requestBody:
|
|
1141
|
+
required: true
|
|
1142
|
+
content:
|
|
1143
|
+
application/json:
|
|
1144
|
+
schema:
|
|
1145
|
+
type: object
|
|
1146
|
+
required: [harness]
|
|
1147
|
+
properties:
|
|
1148
|
+
harness:
|
|
1149
|
+
type: string
|
|
1150
|
+
harnessId:
|
|
1151
|
+
type: string
|
|
1152
|
+
jobId:
|
|
1153
|
+
type: string
|
|
1154
|
+
skill:
|
|
1155
|
+
type: string
|
|
1156
|
+
partnerProfile:
|
|
1157
|
+
type: string
|
|
1158
|
+
autoImprove:
|
|
1159
|
+
type: boolean
|
|
1160
|
+
inputs:
|
|
1161
|
+
type: object
|
|
1162
|
+
responses:
|
|
1163
|
+
'202':
|
|
1164
|
+
description: Hosted harness accepted
|
|
1165
|
+
'401':
|
|
1166
|
+
description: Unauthorized
|
|
1167
|
+
/v1/jobs/{jobId}:
|
|
1168
|
+
get:
|
|
1169
|
+
operationId: getHostedJob
|
|
1170
|
+
parameters:
|
|
1171
|
+
- in: path
|
|
1172
|
+
name: jobId
|
|
1173
|
+
required: true
|
|
1174
|
+
schema:
|
|
1175
|
+
type: string
|
|
1176
|
+
responses:
|
|
1177
|
+
'200':
|
|
1178
|
+
description: Hosted job state
|
|
1179
|
+
'401':
|
|
1180
|
+
description: Unauthorized
|
|
1181
|
+
'404':
|
|
1182
|
+
description: Job not found
|
|
1183
|
+
/v1/jobs/{jobId}/control:
|
|
1184
|
+
post:
|
|
1185
|
+
operationId: controlHostedJob
|
|
1186
|
+
parameters:
|
|
1187
|
+
- in: path
|
|
1188
|
+
name: jobId
|
|
1189
|
+
required: true
|
|
1190
|
+
schema:
|
|
1191
|
+
type: string
|
|
1192
|
+
requestBody:
|
|
1193
|
+
required: true
|
|
1194
|
+
content:
|
|
1195
|
+
application/json:
|
|
1196
|
+
schema:
|
|
1197
|
+
type: object
|
|
1198
|
+
required: [action]
|
|
1199
|
+
properties:
|
|
1200
|
+
action:
|
|
1201
|
+
type: string
|
|
1202
|
+
enum: [pause, cancel, resume]
|
|
1203
|
+
metadata:
|
|
1204
|
+
type: object
|
|
1205
|
+
responses:
|
|
1206
|
+
'202':
|
|
1207
|
+
description: Hosted job control accepted
|
|
1107
1208
|
'401':
|
|
1108
1209
|
description: Unauthorized
|
|
1210
|
+
'404':
|
|
1211
|
+
description: Job not found
|
|
1212
|
+
'409':
|
|
1213
|
+
description: Job cannot accept the requested control action
|
|
1109
1214
|
/v1/analytics/databricks/export:
|
|
1110
1215
|
post:
|
|
1111
1216
|
operationId: exportDatabricksBundle
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thumbgate",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "ThumbGate — Make your AI coding agent self-improving. Every mistake becomes a prevention rule that physically blocks the agent from repeating it. Feedback-driven enforcement via PreToolUse hooks, Thompson Sampling for adaptive gates, SQLite+FTS5 lesson DB, and LanceDB vector search. Your agent gets smarter with every session.",
|
|
5
5
|
"homepage": "https://thumbgate-production.up.railway.app",
|
|
6
6
|
"repository": {
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"social:post-everywhere:dry": "node scripts/post-everywhere.js --dry-run",
|
|
67
67
|
"social:reply-monitor": "node scripts/social-reply-monitor.js",
|
|
68
68
|
"social:reply-monitor:dry": "node scripts/social-reply-monitor.js --dry-run",
|
|
69
|
-
"test": "npm run test:schema && npm run test:loop && npm run test:dpo && npm run test:kto && npm run test:api && npm run test:proof && npm run test:e2e && npm run test:rlaif && npm run test:attribution && npm run test:quality && npm run test:intelligence && npm run test:training-export && npm run test:deployment && npm run test:operational-integrity && npm run test:workflow && npm run test:billing && npm run test:cli && npm run test:watcher && npm run test:autoresearch && npm run test:ops && npm run test:tessl && npm run test:gates && npm run test:evoskill && npm run test:gates-hardening && npm run test:workers && npm run test:social-analytics && npm run test:memalign && npm run test:xmemory-lite && npm run test:filesystem-search && npm run test:zernio && npm run test:obsidian-export && npm run test:lesson-db && npm run test:lesson-rotation && npm run test:memory-dedup && npm run test:feedback-quality && npm run test:sync-version && npm run test:check-congruence && npm run test:tool-registry && npm run test:feedback-to-rules && npm run test:memory-firewall && npm run test:belief-update && npm run test:hosted-config && npm run test:cloudflare-sandbox && npm run test:mcp-config && npm run test:plan-gate && npm run test:pulse && npm run test:semantic-layer && npm run test:data-pipeline && npm run test:optimize-context && npm run test:principle-extractor && npm run test:analytics-window && npm run test:funnel-analytics && npm run test:experiment-tracker && npm run test:build-metadata && npm run test:context-engine && npm run test:hf-papers && npm run test:marketing-experiment && npm run test:seo-gsd && npm run test:verify-run && npm run test:export-dpo-pairs && npm run test:license && npm run test:bot-detector && npm run test:postinstall && npm run test:funnel-invariants && npm run test:cli-telemetry && npm run test:pro-parity && npm run test:model-tier-router && npm run test:computer-use-firewall && npm run test:skill-exporter && npm run test:statusline && npm run test:evolution && npm run test:org-dashboard && npm run test:multi-hop-recall && npm run test:synthetic-dpo && npm run test:thumbgate-skill && npm run test:learn-hub && npm run test:feedback-fallback && npm run test:metaclaw && npm run test:server-lock && npm run test:control-tower && npm run test:pii-scanner && npm run test:data-governance && npm run test:lesson-inference && npm run test:lesson-retrieval && npm run test:reflector-agent && npm run test:feedback-session && npm run test:feedback-history-distiller && npm run test:hallucination-detector && npm run test:history-distiller && npm run test:predictive-insights && npm run test:prove-predictive-insights && npm run test:statusbar-cli && npm run test:generate-instagram-card && npm run test:instagram-thumbgate-post && npm run test:publish-instagram-thumbgate && npm run test:lesson-synthesis && npm run test:background-governance && npm run test:memory-migration && npm run test:prompt-dlp && npm run test:ephemeral-store && npm run test:agent-security && npm run test:skill-progressive && npm run test:per-step-scoring && npm run test:weekly-auto-post && npm run test:social-quality-gate && npm run test:a2ui-engine && npm run test:gate-satisfy && npm run test:money-watcher && npm run test:utm && npm run test:product-feedback && npm run test:feedback-root-consolidator && npm run test:engagement-audit && npm run test:install-growth-automation && npm run test:publish-thumbgate-launch && npm run test:reconcile-thumbgate-campaign && npm run test:reddit-publisher && npm run test:schedule-thumbgate-campaign && npm run test:social-reply-monitor && npm run test:sync-launch-assets",
|
|
69
|
+
"test": "npm run test:schema && npm run test:loop && npm run test:dpo && npm run test:kto && npm run test:api && npm run test:proof && npm run test:e2e && npm run test:rlaif && npm run test:attribution && npm run test:quality && npm run test:intelligence && npm run test:training-export && npm run test:deployment && npm run test:operational-integrity && npm run test:workflow && npm run test:billing && npm run test:cli && npm run test:watcher && npm run test:autoresearch && npm run test:ops && npm run test:tessl && npm run test:gates && npm run test:evoskill && npm run test:gates-hardening && npm run test:workers && npm run test:social-analytics && npm run test:memalign && npm run test:xmemory-lite && npm run test:filesystem-search && npm run test:zernio && npm run test:obsidian-export && npm run test:lesson-db && npm run test:lesson-rotation && npm run test:memory-dedup && npm run test:feedback-quality && npm run test:sync-version && npm run test:check-congruence && npm run test:tool-registry && npm run test:feedback-to-rules && npm run test:memory-firewall && npm run test:belief-update && npm run test:hosted-config && npm run test:cloudflare-sandbox && npm run test:mcp-config && npm run test:plan-gate && npm run test:pulse && npm run test:semantic-layer && npm run test:data-pipeline && npm run test:optimize-context && npm run test:principle-extractor && npm run test:analytics-window && npm run test:funnel-analytics && npm run test:experiment-tracker && npm run test:build-metadata && npm run test:context-engine && npm run test:hf-papers && npm run test:marketing-experiment && npm run test:seo-gsd && npm run test:verify-run && npm run test:export-dpo-pairs && npm run test:export-hf-dataset && npm run test:license && npm run test:bot-detector && npm run test:postinstall && npm run test:funnel-invariants && npm run test:cli-telemetry && npm run test:pro-parity && npm run test:model-tier-router && npm run test:computer-use-firewall && npm run test:skill-exporter && npm run test:statusline && npm run test:evolution && npm run test:org-dashboard && npm run test:multi-hop-recall && npm run test:synthetic-dpo && npm run test:thumbgate-skill && npm run test:learn-hub && npm run test:feedback-fallback && npm run test:metaclaw && npm run test:server-lock && npm run test:control-tower && npm run test:pii-scanner && npm run test:data-governance && npm run test:lesson-inference && npm run test:lesson-retrieval && npm run test:reflector-agent && npm run test:feedback-session && npm run test:feedback-history-distiller && npm run test:hallucination-detector && npm run test:history-distiller && npm run test:predictive-insights && npm run test:prove-predictive-insights && npm run test:statusbar-cli && npm run test:generate-instagram-card && npm run test:instagram-thumbgate-post && npm run test:publish-instagram-thumbgate && npm run test:lesson-synthesis && npm run test:background-governance && npm run test:memory-migration && npm run test:prompt-dlp && npm run test:ephemeral-store && npm run test:agent-security && npm run test:skill-progressive && npm run test:per-step-scoring && npm run test:weekly-auto-post && npm run test:social-quality-gate && npm run test:a2ui-engine && npm run test:gate-satisfy && npm run test:money-watcher && npm run test:utm && npm run test:product-feedback && npm run test:feedback-root-consolidator && npm run test:engagement-audit && npm run test:install-growth-automation && npm run test:publish-thumbgate-launch && npm run test:reconcile-thumbgate-campaign && npm run test:reddit-publisher && npm run test:schedule-thumbgate-campaign && npm run test:social-reply-monitor && npm run test:sync-launch-assets",
|
|
70
70
|
"test:feedback-fallback": "node --test tests/feedback-fallback.test.js",
|
|
71
71
|
"test:metaclaw": "node --test tests/metaclaw-features.test.js",
|
|
72
72
|
"test:server-lock": "node --test tests/server-stdio-lock.test.js",
|
|
@@ -99,12 +99,14 @@
|
|
|
99
99
|
"test:funnel-analytics": "node --test tests/funnel-analytics.test.js",
|
|
100
100
|
"test:experiment-tracker": "node --test tests/experiment-tracker.test.js",
|
|
101
101
|
"test:build-metadata": "node --test tests/build-metadata.test.js",
|
|
102
|
-
"test:context-engine": "node --test tests/context-engine.test.js",
|
|
102
|
+
"test:context-engine": "node --test tests/context-engine.test.js tests/context-manager.test.js",
|
|
103
103
|
"test:hf-papers": "node --test tests/hf-papers.test.js",
|
|
104
104
|
"test:marketing-experiment": "node --test tests/marketing-experiment.test.js",
|
|
105
105
|
"test:seo-gsd": "node --test tests/seo-gsd.test.js",
|
|
106
106
|
"test:verify-run": "node --test tests/verify-run.test.js",
|
|
107
107
|
"test:export-dpo-pairs": "node --test tests/export-dpo-pairs.test.js",
|
|
108
|
+
"test:export-hf-dataset": "node --test tests/export-hf-dataset.test.js",
|
|
109
|
+
"export:hf": "node scripts/export-hf-dataset.js",
|
|
108
110
|
"seo:gsd": "node scripts/seo-gsd.js plan",
|
|
109
111
|
"seo:gsd:write": "node scripts/seo-gsd.js plan --write",
|
|
110
112
|
"test:congruence": "node scripts/check-congruence.js",
|
|
@@ -115,7 +117,7 @@
|
|
|
115
117
|
"test:loop": "node scripts/feedback-loop.js --test",
|
|
116
118
|
"test:dpo": "node scripts/export-dpo-pairs.js --test",
|
|
117
119
|
"test:kto": "node --test tests/export-kto.test.js",
|
|
118
|
-
"test:api": "node --test --test-concurrency=1 tests/api-server.test.js tests/api-auth-config.test.js tests/mcp-server.test.js tests/adapters.test.js tests/openapi-parity.test.js tests/budget-guard.test.js tests/contextfs.test.js tests/pack-templates.test.js tests/dashboard.test.js tests/dashboard-render-spec.test.js tests/dashboard-html.test.js tests/agent-readiness.test.js tests/mcp-policy.test.js tests/subagent-profiles.test.js tests/intent-router.test.js tests/internal-agent-bootstrap.test.js tests/lesson-search.test.js tests/thumbgate-search.test.js tests/rubric-engine.test.js tests/self-healing-check.test.js tests/self-heal.test.js tests/feedback-schema.test.js tests/thompson-sampling.test.js tests/feedback-sequences.test.js tests/diversity-tracking.test.js tests/vector-store.test.js tests/feedback-attribution.test.js tests/hybrid-feedback-context.test.js tests/loop-closure.test.js tests/code-reasoning.test.js tests/feedback-loop.test.js tests/feedback-inbox-read.test.js tests/feedback-to-memory.test.js tests/test-coverage.test.js tests/version-metadata.test.js tests/claude-mcpb.test.js tests/claude-codex-bridge.test.js tests/cursor-plugin.test.js tests/codex-plugin.test.js tests/telemetry-analytics.test.js tests/public-landing.test.js tests/pro-landing.test.js tests/local-model-profile.test.js tests/risk-scorer.test.js tests/context-compaction.test.js tests/reminder-engine.test.js tests/post-to-x.test.js tests/verification-loop.test.js tests/async-job-runner.test.js tests/commerce-quality.test.js tests/recall-limit.test.js tests/problem-detail.test.js tests/natural-language-harness.test.js tests/settings-hierarchy.test.js",
|
|
120
|
+
"test:api": "node --test --test-concurrency=1 tests/api-server.test.js tests/api-auth-config.test.js tests/mcp-server.test.js tests/adapters.test.js tests/openapi-parity.test.js tests/budget-guard.test.js tests/contextfs.test.js tests/pack-templates.test.js tests/dashboard.test.js tests/dashboard-render-spec.test.js tests/dashboard-html.test.js tests/agent-readiness.test.js tests/mcp-policy.test.js tests/subagent-profiles.test.js tests/intent-router.test.js tests/internal-agent-bootstrap.test.js tests/job-api.test.js tests/lesson-search.test.js tests/thumbgate-search.test.js tests/rubric-engine.test.js tests/self-healing-check.test.js tests/self-heal.test.js tests/feedback-schema.test.js tests/thompson-sampling.test.js tests/feedback-sequences.test.js tests/diversity-tracking.test.js tests/vector-store.test.js tests/feedback-attribution.test.js tests/hybrid-feedback-context.test.js tests/loop-closure.test.js tests/code-reasoning.test.js tests/feedback-loop.test.js tests/feedback-inbox-read.test.js tests/feedback-to-memory.test.js tests/test-coverage.test.js tests/version-metadata.test.js tests/claude-mcpb.test.js tests/claude-codex-bridge.test.js tests/cursor-plugin.test.js tests/codex-plugin.test.js tests/telemetry-analytics.test.js tests/public-landing.test.js tests/pro-landing.test.js tests/local-model-profile.test.js tests/risk-scorer.test.js tests/context-compaction.test.js tests/reminder-engine.test.js tests/post-to-x.test.js tests/verification-loop.test.js tests/async-job-runner.test.js tests/commerce-quality.test.js tests/recall-limit.test.js tests/problem-detail.test.js tests/natural-language-harness.test.js tests/settings-hierarchy.test.js",
|
|
119
121
|
"test:proof": "node --test tests/prove-adapters.test.js tests/prove-attribution.test.js tests/prove-cloudflare-sandbox.test.js tests/prove-data-quality.test.js tests/prove-intelligence.test.js tests/prove-lancedb.test.js tests/prove-loop-closure.test.js tests/prove-subway-upgrades.test.js tests/prove-training-export.test.js tests/prove-local-intelligence.test.js tests/prove-workflow-contract.test.js tests/prove-autoresearch.test.js tests/prove-claim-verification.test.js tests/prove-data-pipeline.test.js tests/prove-evolution.test.js tests/prove-harnesses.test.js tests/prove-runtime.test.js tests/prove-seo-gsd.test.js tests/prove-settings.test.js tests/prove-xmemory.test.js && node --test tests/prove-automation.test.js",
|
|
120
122
|
"test:e2e": "node --test tests/e2e-pipeline.test.js tests/e2e-product-flows.test.js tests/e2e-coverage-contract.test.js",
|
|
121
123
|
"test:rlaif": "node --test tests/rlaif-self-audit.test.js tests/dpo-optimizer.test.js tests/meta-policy.test.js",
|
|
@@ -133,7 +135,7 @@
|
|
|
133
135
|
"test:autoresearch": "node --test tests/autoresearch.test.js",
|
|
134
136
|
"test:ops": "node --test tests/adk-consolidator.test.js tests/anthropic-partner-strategy.test.js tests/auto-promote-gates.test.js tests/auto-wire-hooks.test.js tests/claude-skill.test.js tests/codegraph-context.test.js tests/commercial-signals.test.js tests/delegation-runtime.test.js tests/disagreement-mining.test.js tests/failure-diagnostics.test.js tests/gate-stats.test.js tests/github-billing.test.js tests/markdown-escape.test.js tests/mcp-tools-gates.test.js tests/project-bayes-e2e.test.js tests/project-bayes.test.js tests/rate-limiter.test.js tests/schedule-manager.test.js tests/session-handoff.test.js tests/skill-generator.test.js tests/smart-learning.test.js tests/spike-and-sink.test.js tests/stripe-webhook-route.test.js tests/train-from-feedback.test.js tests/workflow-hardening-sprint.test.js tests/test-suite-parity.test.js tests/a2ui-engine.test.js tests/webhook-delivery.test.js",
|
|
135
137
|
"test:tessl": "node --test tests/tessl-export.test.js",
|
|
136
|
-
"test:gates": "node --test tests/gate-templates.test.js tests/gates-engine.test.js tests/claim-verification.test.js tests/secret-scanner.test.js tests/prompt-guard.test.js tests/audit-trail.test.js tests/profile-router.test.js",
|
|
138
|
+
"test:gates": "node --test tests/gate-templates.test.js tests/gates-engine.test.js tests/claim-verification.test.js tests/secret-scanner.test.js tests/prompt-guard.test.js tests/audit-trail.test.js tests/profile-router.test.js tests/workflow-sentinel.test.js",
|
|
137
139
|
"test:workers": "npm --prefix workers ci && npm --prefix workers test",
|
|
138
140
|
"test:evoskill": "node --test tests/evoskill.test.js",
|
|
139
141
|
"test:gates-hardening": "node --test tests/gates-hardening.test.js",
|