thumbgate 0.9.13 → 1.0.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 +6 -3
- 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 +32 -1
- package/adapters/opencode/opencode.json +1 -1
- package/bin/cli.js +53 -3
- package/config/mcp-allowlists.json +10 -0
- package/openapi/openapi.yaml +105 -0
- package/package.json +4 -4
- 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 +29 -5
- 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 +62 -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/feedback-history-distiller.js +7 -1
- package/scripts/feedback-loop.js +10 -4
- package/scripts/feedback-paths.js +142 -10
- package/scripts/feedback-root-consolidator.js +18 -4
- 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/post-everywhere.js +10 -0
- package/scripts/prove-lancedb.js +62 -4
- package/scripts/publish-decision.js +16 -0
- package/scripts/self-healing-check.js +6 -1
- package/scripts/seo-gsd.js +217 -4
- package/scripts/social-analytics/load-env.js +33 -2
- package/scripts/social-analytics/store.js +200 -2
- package/scripts/statusline-cache-path.js +9 -6
- package/scripts/sync-version.js +18 -11
- package/scripts/tool-registry.js +37 -0
- package/scripts/train_from_feedback.py +0 -4
- package/scripts/workflow-sentinel.js +793 -0
- package/src/api/server.js +297 -38
- /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": "0.
|
|
4
|
+
"version": "1.0.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Igor Ganapolsky"
|
|
7
7
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thumbgate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.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
|
@@ -7,7 +7,9 @@ Make your AI coding agent self-improving. One thumbs-down creates a gate that pe
|
|
|
7
7
|
[](LICENSE)
|
|
8
8
|
[](https://thumbgate-production.up.railway.app/checkout/pro?utm_source=github&utm_medium=readme&utm_campaign=badge_cta)
|
|
9
9
|
|
|
10
|
-
**[Pro Page](https://thumbgate-production.up.railway.app/pro?utm_source=github&utm_medium=readme&utm_campaign=pro_page)** · **[Live Dashboard](https://thumbgate-production.up.railway.app/dashboard?utm_source=github&utm_medium=readme&utm_campaign=top_cta)** · **[Pricing](https://thumbgate-production.up.railway.app
|
|
10
|
+
**[Pro Page](https://thumbgate-production.up.railway.app/pro?utm_source=github&utm_medium=readme&utm_campaign=pro_page)** · **[Live Dashboard](https://thumbgate-production.up.railway.app/dashboard?utm_source=github&utm_medium=readme&utm_campaign=top_cta)** · **[Pricing](https://thumbgate-production.up.railway.app/?utm_source=github&utm_medium=readme&utm_campaign=top_cta#pricing)** · **[Setup Guide](https://thumbgate-production.up.railway.app/guide?utm_source=github&utm_medium=readme&utm_campaign=top_cta)**
|
|
11
|
+
|
|
12
|
+
**Popular buyer questions:** **[How to stop repeated AI agent mistakes](https://thumbgate-production.up.railway.app/guides/stop-repeated-ai-agent-mistakes?utm_source=github&utm_medium=readme&utm_campaign=buyer_questions)** · **[Cursor guardrails](https://thumbgate-production.up.railway.app/guides/cursor-agent-guardrails?utm_source=github&utm_medium=readme&utm_campaign=buyer_questions)** · **[Codex CLI guardrails](https://thumbgate-production.up.railway.app/guides/codex-cli-guardrails?utm_source=github&utm_medium=readme&utm_campaign=buyer_questions)** · **[Gemini CLI memory + enforcement](https://thumbgate-production.up.railway.app/guides/gemini-cli-feedback-memory?utm_source=github&utm_medium=readme&utm_campaign=buyer_questions)**
|
|
11
13
|
|
|
12
14
|
### Get Started
|
|
13
15
|
|
|
@@ -15,7 +17,7 @@ Make your AI coding agent self-improving. One thumbs-down creates a gate that pe
|
|
|
15
17
|
|
|
16
18
|
[](https://thumbgate-production.up.railway.app/checkout/pro?utm_source=github&utm_medium=readme&utm_campaign=get_started)
|
|
17
19
|
|
|
18
|
-
Free for individual developers. Pro adds team dashboards, DPO export, and unlimited lesson search. [See pricing →](https://thumbgate-production.up.railway.app
|
|
20
|
+
Free for individual developers. Pro adds team dashboards, DPO export, and unlimited lesson search. [See pricing →](https://thumbgate-production.up.railway.app/?utm_source=github&utm_medium=readme&utm_campaign=pricing_link#pricing)
|
|
19
21
|
|
|
20
22
|
**Paid path for individual operators:** [ThumbGate Pro](https://thumbgate-production.up.railway.app/pro?utm_source=github&utm_medium=readme&utm_campaign=pro_page) is the buyer-ready page for the personal local dashboard, DPO export, and review-ready evidence. It makes the paid upgrade legible before checkout while the self-hosted path below stays optimized for open source evaluation.
|
|
21
23
|
|
|
@@ -142,7 +144,7 @@ Free includes unlimited feedback captures, 5 daily lesson searches, unlimited re
|
|
|
142
144
|
|
|
143
145
|
It does not update model weights. It's context engineering — enforcement that gets smarter every session.
|
|
144
146
|
|
|
145
|
-
**[Get Pro](https://thumbgate-production.up.railway.app/checkout/pro?utm_source=github&utm_medium=readme&utm_campaign=thumbgate)** | **[Start Team Rollout](https://thumbgate-production.up.railway.app
|
|
147
|
+
**[Get Pro](https://thumbgate-production.up.railway.app/checkout/pro?utm_source=github&utm_medium=readme&utm_campaign=thumbgate)** | **[Start Team Rollout](https://thumbgate-production.up.railway.app/?utm_source=github&utm_medium=readme&utm_campaign=team_rollout#workflow-sprint-intake)** | **[Live Dashboard](https://thumbgate-production.up.railway.app/dashboard?utm_source=github&utm_medium=readme&utm_campaign=thumbgate)**
|
|
146
148
|
|
|
147
149
|
## Tech Stack
|
|
148
150
|
|
|
@@ -167,6 +169,7 @@ It does not update model weights. It's context engineering — enforcement that
|
|
|
167
169
|
## Docs
|
|
168
170
|
|
|
169
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
|
|
170
173
|
- [Verification Evidence](docs/VERIFICATION_EVIDENCE.md) — proof artifacts
|
|
171
174
|
- [WORKFLOW.md](WORKFLOW.md) — agent-run contract (scope, hard stops, proof commands)
|
|
172
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@0.
|
|
6
|
+
- `claude/.mcp.json`: example Claude Code MCP config using `npx --yes --package thumbgate@1.0.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@0.
|
|
5
|
+
"args": ["--yes", "--package", "thumbgate@1.0.0", "thumbgate", "serve"]
|
|
6
6
|
}
|
|
7
7
|
},
|
|
8
8
|
"hooks": {
|
|
9
9
|
"preToolUse": {
|
|
10
10
|
"command": "npx",
|
|
11
|
-
"args": ["--yes", "--package", "thumbgate@0.
|
|
11
|
+
"args": ["--yes", "--package", "thumbgate@1.0.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@0.
|
|
4
|
+
args = ["--yes", "--package", "thumbgate@1.0.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@0.
|
|
9
|
+
args = ["--yes", "--package", "thumbgate@1.0.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,10 @@ 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');
|
|
93
100
|
|
|
94
101
|
const PRO_CHECKOUT_URL = 'https://thumbgate-production.up.railway.app/checkout/pro';
|
|
95
102
|
|
|
@@ -111,7 +118,7 @@ const {
|
|
|
111
118
|
finalizeSession: finalizeFeedbackSession,
|
|
112
119
|
} = require('../../scripts/feedback-session');
|
|
113
120
|
|
|
114
|
-
const SERVER_INFO = { name: 'thumbgate-mcp', version: '0.
|
|
121
|
+
const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.0.0' };
|
|
115
122
|
const COMMERCE_CATEGORIES = [
|
|
116
123
|
'product_recommendation',
|
|
117
124
|
'brand_compliance',
|
|
@@ -508,6 +515,16 @@ async function callToolInner(name, args) {
|
|
|
508
515
|
});
|
|
509
516
|
case 'recall':
|
|
510
517
|
return buildRecallResponse(args);
|
|
518
|
+
case 'unified_context': {
|
|
519
|
+
const ctx = assembleUnifiedContext({
|
|
520
|
+
query: args.query || '',
|
|
521
|
+
toolName: args.toolName,
|
|
522
|
+
toolInput: args.toolInput,
|
|
523
|
+
agentType: args.agentType,
|
|
524
|
+
repoPath: args.repoPath,
|
|
525
|
+
});
|
|
526
|
+
return toTextResult(formatUnifiedContext(ctx));
|
|
527
|
+
}
|
|
511
528
|
case 'satisfy_gate': {
|
|
512
529
|
if (!args.gate) {
|
|
513
530
|
throw new Error('gate is required');
|
|
@@ -589,6 +606,20 @@ async function callToolInner(name, args) {
|
|
|
589
606
|
requireVersionNotBehindBase: args.requireVersionNotBehindBase === true,
|
|
590
607
|
branchGovernance: getBranchGovernanceState(),
|
|
591
608
|
}));
|
|
609
|
+
case 'workflow_sentinel':
|
|
610
|
+
return toTextResult(evaluateWorkflowSentinel(args.toolName, {
|
|
611
|
+
command: args.command,
|
|
612
|
+
path: args.filePath,
|
|
613
|
+
changedFiles: Array.isArray(args.changedFiles) ? args.changedFiles : [],
|
|
614
|
+
repoPath: args.repoPath,
|
|
615
|
+
baseBranch: args.baseBranch,
|
|
616
|
+
}, {
|
|
617
|
+
repoPath: args.repoPath,
|
|
618
|
+
baseBranch: args.baseBranch,
|
|
619
|
+
affectedFiles: Array.isArray(args.changedFiles) ? args.changedFiles : undefined,
|
|
620
|
+
requirePrForReleaseSensitive: args.requirePrForReleaseSensitive === true,
|
|
621
|
+
requireVersionNotBehindBase: args.requireVersionNotBehindBase === true,
|
|
622
|
+
}));
|
|
592
623
|
case 'register_claim_gate':
|
|
593
624
|
return toTextResult(registerClaimGate(args.claimPattern, args.requiredActions, args.message));
|
|
594
625
|
case 'gate_stats':
|
package/bin/cli.js
CHANGED
|
@@ -63,6 +63,37 @@ function appendLocalTelemetry(payload) {
|
|
|
63
63
|
} catch (_) { /* telemetry is best-effort */ }
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
function syncActiveProjectContext(options = {}) {
|
|
67
|
+
try {
|
|
68
|
+
// Tests and explicitly scoped CLI calls may pin a feedback root directly.
|
|
69
|
+
// In that case, do not inject a project selection that would cause later
|
|
70
|
+
// reads/writes to escape the requested directory.
|
|
71
|
+
if (
|
|
72
|
+
!options.force &&
|
|
73
|
+
process.env.THUMBGATE_FEEDBACK_DIR &&
|
|
74
|
+
!process.env.THUMBGATE_PROJECT_DIR &&
|
|
75
|
+
!process.env.CLAUDE_PROJECT_DIR
|
|
76
|
+
) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
const {
|
|
80
|
+
resolveProjectDir,
|
|
81
|
+
writeActiveProjectState,
|
|
82
|
+
} = require(path.join(PKG_ROOT, 'scripts', 'feedback-paths'));
|
|
83
|
+
const projectDir = resolveProjectDir({
|
|
84
|
+
cwd: CWD,
|
|
85
|
+
env: process.env,
|
|
86
|
+
includeStored: options.includeStored !== false,
|
|
87
|
+
});
|
|
88
|
+
if (!projectDir) return null;
|
|
89
|
+
process.env.THUMBGATE_PROJECT_DIR = projectDir;
|
|
90
|
+
writeActiveProjectState(projectDir, { env: process.env });
|
|
91
|
+
return projectDir;
|
|
92
|
+
} catch (_) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
66
97
|
function telemetryPing(installId) {
|
|
67
98
|
if (process.env.THUMBGATE_NO_TELEMETRY === '1') return;
|
|
68
99
|
const payloadObject = {
|
|
@@ -411,6 +442,19 @@ function setupCursor() {
|
|
|
411
442
|
return mergeMcpJson(path.join(CWD, '.cursor', 'mcp.json'), 'Cursor', 'project');
|
|
412
443
|
}
|
|
413
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
|
+
|
|
414
458
|
function init() {
|
|
415
459
|
const args = parseArgs(process.argv.slice(3));
|
|
416
460
|
|
|
@@ -482,6 +526,7 @@ function init() {
|
|
|
482
526
|
{ name: 'Gemini', detect: [() => whichExists('gemini'), () => fs.existsSync(path.join(HOME, '.gemini'))], setup: setupGemini },
|
|
483
527
|
{ name: 'Amp', detect: [() => whichExists('amp'), () => fs.existsSync(path.join(HOME, '.amp'))], setup: setupAmp },
|
|
484
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 },
|
|
485
530
|
];
|
|
486
531
|
|
|
487
532
|
for (const p of platforms) {
|
|
@@ -1158,7 +1203,8 @@ function install() {
|
|
|
1158
1203
|
setupCodex(),
|
|
1159
1204
|
setupGemini(),
|
|
1160
1205
|
setupCursor(),
|
|
1161
|
-
setupAmp()
|
|
1206
|
+
setupAmp(),
|
|
1207
|
+
setupForge()
|
|
1162
1208
|
];
|
|
1163
1209
|
const success = results.some(r => r === true);
|
|
1164
1210
|
if (success) {
|
|
@@ -1178,12 +1224,14 @@ async function gateCheck() {
|
|
|
1178
1224
|
}
|
|
1179
1225
|
|
|
1180
1226
|
function cacheUpdate() {
|
|
1227
|
+
syncActiveProjectContext();
|
|
1181
1228
|
const payload = readStdinText();
|
|
1182
1229
|
const { updateCacheFromEvent } = require(path.join(PKG_ROOT, 'scripts', 'hook-thumbgate-cache-updater'));
|
|
1183
1230
|
updateCacheFromEvent(payload ? JSON.parse(payload) : {});
|
|
1184
1231
|
}
|
|
1185
1232
|
|
|
1186
1233
|
function statuslineRender() {
|
|
1234
|
+
syncActiveProjectContext();
|
|
1187
1235
|
const payload = readStdinText();
|
|
1188
1236
|
const output = execFileSync('bash', [path.join(PKG_ROOT, 'scripts', 'statusline.sh')], {
|
|
1189
1237
|
encoding: 'utf8',
|
|
@@ -1194,6 +1242,7 @@ function statuslineRender() {
|
|
|
1194
1242
|
}
|
|
1195
1243
|
|
|
1196
1244
|
function hookAutoCapture() {
|
|
1245
|
+
syncActiveProjectContext();
|
|
1197
1246
|
const prompt = process.env.CLAUDE_USER_PROMPT || process.env.THUMBGATE_USER_PROMPT || readStdinText().trim();
|
|
1198
1247
|
const { evaluatePromptGuard } = require(path.join(PKG_ROOT, 'scripts', 'prompt-guard'));
|
|
1199
1248
|
const { processInlineFeedback, formatCliOutput } = require(path.join(PKG_ROOT, 'scripts', 'cli-feedback'));
|
|
@@ -1233,6 +1282,7 @@ function hookAutoCapture() {
|
|
|
1233
1282
|
}
|
|
1234
1283
|
|
|
1235
1284
|
function sessionStart() {
|
|
1285
|
+
syncActiveProjectContext();
|
|
1236
1286
|
const { analyzeFeedback } = require(path.join(PKG_ROOT, 'scripts', 'feedback-loop'));
|
|
1237
1287
|
const { refreshStatuslineCache } = require(path.join(PKG_ROOT, 'scripts', 'hook-thumbgate-cache-updater'));
|
|
1238
1288
|
refreshStatuslineCache(analyzeFeedback());
|
|
@@ -1285,11 +1335,11 @@ function help() {
|
|
|
1285
1335
|
console.log('');
|
|
1286
1336
|
console.log('Commands:');
|
|
1287
1337
|
console.log(' init Scaffold .thumbgate/ config + MCP server in current project');
|
|
1288
|
-
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)');
|
|
1289
1339
|
console.log(' --wire-hooks Wire hooks only (auto-detect agent, skip scaffolding)');
|
|
1290
1340
|
console.log(' --dry-run Preview hook changes without writing');
|
|
1291
1341
|
console.log(' install-mcp Install ThumbGate MCP server into Claude Code settings (--project for local)');
|
|
1292
|
-
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');
|
|
1293
1343
|
console.log(' gate-check Internal: evaluate a PreToolUse payload from stdin');
|
|
1294
1344
|
console.log(' cache-update Internal: refresh the Claude statusline cache from stdin');
|
|
1295
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",
|
|
@@ -36,6 +37,7 @@
|
|
|
36
37
|
"track_action",
|
|
37
38
|
"verify_claim",
|
|
38
39
|
"check_operational_integrity",
|
|
40
|
+
"workflow_sentinel",
|
|
39
41
|
"register_claim_gate",
|
|
40
42
|
"gate_stats",
|
|
41
43
|
"dashboard",
|
|
@@ -56,6 +58,7 @@
|
|
|
56
58
|
"append_feedback_context",
|
|
57
59
|
"finalize_feedback_session",
|
|
58
60
|
"recall",
|
|
61
|
+
"unified_context",
|
|
59
62
|
"search_lessons",
|
|
60
63
|
"retrieve_lessons",
|
|
61
64
|
"search_thumbgate",
|
|
@@ -69,6 +72,7 @@
|
|
|
69
72
|
"track_action",
|
|
70
73
|
"verify_claim",
|
|
71
74
|
"check_operational_integrity",
|
|
75
|
+
"workflow_sentinel",
|
|
72
76
|
"feedback_stats",
|
|
73
77
|
"feedback_summary",
|
|
74
78
|
"estimate_uncertainty",
|
|
@@ -88,12 +92,14 @@
|
|
|
88
92
|
"track_action",
|
|
89
93
|
"verify_claim",
|
|
90
94
|
"check_operational_integrity",
|
|
95
|
+
"workflow_sentinel",
|
|
91
96
|
"prevention_rules",
|
|
92
97
|
"feedback_stats",
|
|
93
98
|
"feedback_summary"
|
|
94
99
|
],
|
|
95
100
|
"readonly": [
|
|
96
101
|
"recall",
|
|
102
|
+
"unified_context",
|
|
97
103
|
"feedback_summary",
|
|
98
104
|
"search_lessons",
|
|
99
105
|
"retrieve_lessons",
|
|
@@ -110,6 +116,7 @@
|
|
|
110
116
|
"get_branch_governance",
|
|
111
117
|
"verify_claim",
|
|
112
118
|
"check_operational_integrity",
|
|
119
|
+
"workflow_sentinel",
|
|
113
120
|
"gate_stats",
|
|
114
121
|
"dashboard",
|
|
115
122
|
"settings_status",
|
|
@@ -120,6 +127,7 @@
|
|
|
120
127
|
],
|
|
121
128
|
"dispatch": [
|
|
122
129
|
"recall",
|
|
130
|
+
"unified_context",
|
|
123
131
|
"feedback_summary",
|
|
124
132
|
"search_lessons",
|
|
125
133
|
"retrieve_lessons",
|
|
@@ -135,6 +143,7 @@
|
|
|
135
143
|
"get_branch_governance",
|
|
136
144
|
"verify_claim",
|
|
137
145
|
"check_operational_integrity",
|
|
146
|
+
"workflow_sentinel",
|
|
138
147
|
"gate_stats",
|
|
139
148
|
"dashboard",
|
|
140
149
|
"settings_status",
|
|
@@ -156,6 +165,7 @@
|
|
|
156
165
|
"get_branch_governance",
|
|
157
166
|
"verify_claim",
|
|
158
167
|
"check_operational_integrity",
|
|
168
|
+
"workflow_sentinel",
|
|
159
169
|
"settings_status"
|
|
160
170
|
]
|
|
161
171
|
}
|
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
|