thumbgate 1.27.8 → 1.27.10
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/plugin.json +1 -1
- package/.well-known/llms.txt +1 -2
- package/.well-known/mcp/server-card.json +1 -1
- package/README.md +4 -2
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/mcp/server-stdio.js +1 -1
- package/adapters/opencode/opencode.json +1 -1
- package/bin/cli.js +259 -78
- package/config/gate-templates.json +228 -0
- package/config/gates/claim-verification.json +18 -0
- package/package.json +14 -21
- package/public/blog.html +30 -0
- package/public/compare/adopt-ai.html +219 -0
- package/public/compare/agentix-labs.html +197 -0
- package/public/compare/ai-experience-orchestration.html +216 -0
- package/public/compare/anthropic-claude-for-legal.html +260 -0
- package/public/compare/anthropic-containment.html +280 -0
- package/public/compare/arcade.html +175 -0
- package/public/compare/arcjet.html +239 -0
- package/public/compare/bumblebee.html +307 -0
- package/public/compare/claude-code-hooks.html +294 -0
- package/public/compare/databricks-unity-ai-gateway.html +215 -0
- package/public/compare/fallow.html +351 -0
- package/public/compare/heidi.html +233 -0
- package/public/compare/mem0.html +342 -0
- package/public/compare/oak-and-sparrow-gatekeeper.html +289 -0
- package/public/compare/rein.html +236 -0
- package/public/compare/sigmashake.html +256 -0
- package/public/compare/speclock.html +342 -0
- package/public/compare.html +2 -0
- package/public/guides/agent-harness-optimization.html +342 -0
- package/public/guides/agentic-web-governance.html +406 -0
- package/public/guides/ai-agent-governance-sprint.html +415 -0
- package/public/guides/ai-agent-pre-action-approval-gates.html +401 -0
- package/public/guides/ai-agent-workflow-migration-checklist.html +392 -0
- package/public/guides/ai-deployment-readiness.html +415 -0
- package/public/guides/ai-mode-ads-agent-governance.html +401 -0
- package/public/guides/ai-search-topical-presence.html +342 -0
- package/public/guides/autoresearch-agent-safety.html +342 -0
- package/public/guides/background-agent-governance.html +358 -0
- package/public/guides/best-tools-stop-ai-agents-breaking-production.html +363 -0
- package/public/guides/browser-automation-safety.html +342 -0
- package/public/guides/chatgpt-ads-trust.html +353 -0
- package/public/guides/claude-code-feedback.html +339 -0
- package/public/guides/claude-code-prevent-repeated-mistakes.html +161 -0
- package/public/guides/claude-code-skills-guardrails.html +343 -0
- package/public/guides/claude-desktop.html +356 -0
- package/public/guides/code-knowledge-graph-guardrails.html +365 -0
- package/public/guides/codex-cli-guardrails.html +339 -0
- package/public/guides/cursor-agent-guardrails.html +339 -0
- package/public/guides/cursor-prevent-repeated-mistakes.html +161 -0
- package/public/guides/database-agent-safety.html +406 -0
- package/public/guides/deepseek-v4-runtime-guardrails.html +346 -0
- package/public/guides/developer-machine-supply-chain-guardrails.html +358 -0
- package/public/guides/gcp-mcp-guardrails.html +147 -0
- package/public/guides/gemini-cli-feedback-memory.html +339 -0
- package/public/guides/gpt-5-5-model-evaluation.html +358 -0
- package/public/guides/internal-ai-engineering-stack-guardrails.html +348 -0
- package/public/guides/long-running-agent-context-management.html +346 -0
- package/public/guides/mcp-tool-governance.html +401 -0
- package/public/guides/multica-thumbgate-setup.html +134 -0
- package/public/guides/native-messaging-host-security.html +342 -0
- package/public/guides/policy-engine-pre-action-gates.html +346 -0
- package/public/guides/pre-action-checks.html +342 -0
- package/public/guides/pretooluse-hooks-vs-advisory-prompt-rules.html +342 -0
- package/public/guides/prompt-tricks-to-workflow-rules.html +365 -0
- package/public/guides/proxy-pointer-rag-guardrails.html +352 -0
- package/public/guides/rag-precision-tuning-guardrails.html +352 -0
- package/public/guides/reasoning-compression-guardrails.html +346 -0
- package/public/guides/relational-knowledge-ai-recommendations.html +342 -0
- package/public/guides/roo-code-alternative-cline.html +339 -0
- package/public/guides/semantic-programmatic-seo-guardrails.html +352 -0
- package/public/guides/seo-agent-skills-guardrails.html +344 -0
- package/public/guides/stop-repeated-ai-agent-mistakes.html +342 -0
- package/public/index.html +192 -50
- package/public/learn/ac-dc-runtime-enforcement.html +277 -0
- package/public/learn/agent-harness-pattern.html +181 -0
- package/public/learn/agent-identity-connector-governance.html +146 -0
- package/public/learn/agent-swarms-shared-gates.html +173 -0
- package/public/learn/agentic-enterprise-context-brain.html +117 -0
- package/public/learn/agentic-os-team-governance.html +146 -0
- package/public/learn/ai-agent-governance.html +158 -0
- package/public/learn/ai-agent-persistent-memory.html +211 -0
- package/public/learn/anthropomorphic-claim-gates.html +180 -0
- package/public/learn/background-agent-control-layer.html +184 -0
- package/public/learn/claude-code-goal-with-rubrics.html +205 -0
- package/public/learn/codex-role-plugins-need-governance.html +125 -0
- package/public/learn/cost-aware-agent-gate-routing.html +173 -0
- package/public/learn/databricks-unity-ai-gateway-runtime-governance.html +157 -0
- package/public/learn/deterministic-agent-workflows.html +185 -0
- package/public/learn/feedback-loop-vs-decision-layer.html +283 -0
- package/public/learn/from-prototype-to-production.html +223 -0
- package/public/learn/learn.css +51 -0
- package/public/learn/mcp-pre-action-checks-explained.html +172 -0
- package/public/learn/pretix-stripe-connect-marketplaces.html +161 -0
- package/public/learn/regulated-agent-execution-boundary.html +196 -0
- package/public/learn/spec-driven-development.html +168 -0
- package/public/learn/stop-ai-agent-force-push.html +134 -0
- package/public/learn/vibe-coding-safety-net.html +142 -0
- package/public/learn.html +34 -50
- package/public/numbers.html +2 -2
- package/public/pro.html +6 -6
- package/scripts/cli-schema.js +10 -22
- package/scripts/dashboard-chat.js +1 -2
- package/scripts/document-intake.js +49 -1
- package/scripts/gemini-embedding-policy.js +1 -2
- package/scripts/hook-stop-anti-claim.js +103 -42
- package/scripts/hosted-config.js +12 -0
- package/scripts/plausible-domain-config.js +1 -3
- package/scripts/reddit-browser-notification-watch.js +230 -0
- package/scripts/seo-gsd.js +0 -239
- package/scripts/tool-registry.js +2 -2
- package/scripts/vector-store.js +0 -44
- package/scripts/workspace-evolver.js +2 -62
- package/src/api/server.js +126 -335
- package/adapters/policy-engine/ethicore-guardian-client.js +0 -68
- package/adapters/policy-engine/thumbgate-policy-engine-adapter.js +0 -260
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thumbgate",
|
|
3
3
|
"description": "One 👎 becomes a hard rule the agent cannot bypass. Captures thumbs-down feedback, distills it into PreToolUse Pre-Action Checks, enforced across every future Claude Code session.",
|
|
4
|
-
"version": "1.27.
|
|
4
|
+
"version": "1.27.7",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Igor Ganapolsky",
|
|
7
7
|
"email": "ig5973700@gmail.com",
|
package/.well-known/llms.txt
CHANGED
|
@@ -64,11 +64,10 @@ npx thumbgate init --agent claude-code
|
|
|
64
64
|
- Agent discovery: https://thumbgate.ai/.well-known/mcp.json
|
|
65
65
|
- Progressive tool index: https://thumbgate.ai/.well-known/mcp/tools.json
|
|
66
66
|
- Context footprint report: https://thumbgate.ai/.well-known/mcp/footprint.json
|
|
67
|
-
- Headroom context compression guardrails: https://thumbgate.ai/guides/headroom-context-compression-guardrails
|
|
68
|
-
- Sovereign coding model guardrails: https://thumbgate.ai/guides/sovereign-coding-model-guardrails
|
|
69
67
|
- Agentic web governance: https://thumbgate.ai/guides/agentic-web-governance
|
|
70
68
|
- AI Mode ads and agent governance: https://thumbgate.ai/guides/ai-mode-ads-agent-governance
|
|
71
69
|
- MCP tool governance: https://thumbgate.ai/guides/mcp-tool-governance
|
|
70
|
+
- Policy engines need pre-action gates: https://thumbgate.ai/guides/policy-engine-pre-action-gates
|
|
72
71
|
- AI agent pre-action approval gates: https://thumbgate.ai/guides/ai-agent-pre-action-approval-gates
|
|
73
72
|
- Agent skills: https://thumbgate.ai/.well-known/mcp/skills.json
|
|
74
73
|
- MCP applications: https://thumbgate.ai/.well-known/mcp/applications.json
|
package/README.md
CHANGED
|
@@ -16,6 +16,10 @@ The product is a self-improving enforcement layer: thumbs-down feedback, prompt
|
|
|
16
16
|
<img src="docs/media/thumbgate-demo.gif" alt="ThumbGate blocking an AI agent's dangerous commands (rm -rf, force-push, chmod 777) in real time, while letting safe commands through" width="820" />
|
|
17
17
|
</p>
|
|
18
18
|
|
|
19
|
+
<p align="center">
|
|
20
|
+
<img src="docs/diagrams/pre-action-gate-loop.svg" alt="ThumbGate pre-action gate loop: agent intent, PreToolUse gate, block or allow with audit receipt" width="920" />
|
|
21
|
+
</p>
|
|
22
|
+
|
|
19
23
|
```
|
|
20
24
|
Agent tries: rm -rf tests/
|
|
21
25
|
ThumbGate: ⛔ BLOCKED — "Never delete test directories"
|
|
@@ -384,8 +388,6 @@ npx thumbgate model-candidates --workload=dashboard-analysis --provider=openai -
|
|
|
384
388
|
npx thumbgate native-messaging-audit # inspect local browser bridges and extension hosts
|
|
385
389
|
npx thumbgate dashboard --open # open local project-scoped dashboard in browser
|
|
386
390
|
thumbgate-dashboard # standalone browser dashboard shortcut (run '/project:thumbgate-dashboard' in Claude/Grok)
|
|
387
|
-
npx thumbgate check-update # check if a new version is available on npm/GitHub
|
|
388
|
-
npx thumbgate self-update # update ThumbGate to the latest version globally
|
|
389
391
|
npx thumbgate serve # start MCP server on stdio
|
|
390
392
|
npx thumbgate bench # run reliability benchmark
|
|
391
393
|
npx thumbgate bench --programbench-smoke # include cleanroom whole-repo proof lane
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
"mcpServers": {
|
|
3
3
|
"thumbgate": {
|
|
4
4
|
"command": "npx",
|
|
5
|
-
"args": ["--yes", "--package", "thumbgate@1.27.
|
|
5
|
+
"args": ["--yes", "--package", "thumbgate@1.27.7", "thumbgate", "serve"]
|
|
6
6
|
}
|
|
7
7
|
},
|
|
8
8
|
"hooks": {
|
|
9
9
|
"preToolUse": {
|
|
10
10
|
"command": "npx",
|
|
11
|
-
"args": ["--yes", "--package", "thumbgate@1.27.
|
|
11
|
+
"args": ["--yes", "--package", "thumbgate@1.27.7", "thumbgate", "gate-check"]
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
}
|
|
@@ -231,7 +231,7 @@ const {
|
|
|
231
231
|
finalizeSession: finalizeFeedbackSession,
|
|
232
232
|
} = require('../../scripts/feedback-session');
|
|
233
233
|
|
|
234
|
-
const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.27.
|
|
234
|
+
const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.27.7' };
|
|
235
235
|
const COMMERCE_CATEGORIES = [
|
|
236
236
|
'product_recommendation',
|
|
237
237
|
'brand_compliance',
|
package/bin/cli.js
CHANGED
|
@@ -2188,26 +2188,6 @@ function pulse() {
|
|
|
2188
2188
|
});
|
|
2189
2189
|
}
|
|
2190
2190
|
|
|
2191
|
-
function checkUpdateCmd() {
|
|
2192
|
-
const { checkUpdate } = require(path.join(PKG_ROOT, 'scripts', 'check-update'));
|
|
2193
|
-
const args = parseArgs(process.argv.slice(3));
|
|
2194
|
-
checkUpdate({ verbose: !args.json, force: args.force }).then((res) => {
|
|
2195
|
-
if (args.json) {
|
|
2196
|
-
console.log(JSON.stringify(res, null, 2));
|
|
2197
|
-
}
|
|
2198
|
-
process.exit(0);
|
|
2199
|
-
}).catch((err) => {
|
|
2200
|
-
console.error(err && err.message ? err.message : err);
|
|
2201
|
-
process.exit(1);
|
|
2202
|
-
});
|
|
2203
|
-
}
|
|
2204
|
-
|
|
2205
|
-
function selfUpdateCmd() {
|
|
2206
|
-
const { selfUpdate } = require(path.join(PKG_ROOT, 'scripts', 'check-update'));
|
|
2207
|
-
const success = selfUpdate();
|
|
2208
|
-
process.exit(success ? 0 : 1);
|
|
2209
|
-
}
|
|
2210
|
-
|
|
2211
2191
|
function dispatchBrief() {
|
|
2212
2192
|
const args = parseArgs(process.argv.slice(3));
|
|
2213
2193
|
const {
|
|
@@ -3171,7 +3151,6 @@ const SUBCOMMAND_HELP = {
|
|
|
3171
3151
|
lessons: 'Usage: npx thumbgate lessons [--query="..."] [--limit=N]\n\nSearch the lesson database (Pro feature).',
|
|
3172
3152
|
search: 'Usage: npx thumbgate search <query>\n\nSearch ThumbGate knowledge base (Pro feature).',
|
|
3173
3153
|
'gate-check': 'Usage: npx thumbgate gate-check\n\nPreToolUse hook interface: reads tool call JSON from stdin, outputs gate verdict.',
|
|
3174
|
-
'hermes-gate': 'Usage: npx thumbgate hermes-gate\n\nNous Research Hermes Agent pre_tool_call shell hook: reads Hermes tool-call JSON from stdin, runs the ThumbGate gate pipeline (strict by default), and outputs {"decision":"block","reason":...} to veto or {} to allow. Gates terminal/patch/skill_manage etc. See adapters/hermes/config.yaml.',
|
|
3175
3154
|
'break-glass': 'Usage: npx thumbgate break-glass --reason="why" [--ttl=5m] [--json]\n\nShort-lived recovery path for over-firing gates. Allows hook settings edits and satisfies PR-create/thread-check gates without disabling core destructive-action protections.',
|
|
3176
3155
|
serve: 'Usage: npx thumbgate serve\n\nStart the MCP stdio server. This is for agent runtimes, not the local HTTP dashboard.',
|
|
3177
3156
|
mcp: 'Usage: npx thumbgate mcp\n\nAlias for `thumbgate serve`.',
|
|
@@ -3189,6 +3168,11 @@ const SUBCOMMAND_HELP = {
|
|
|
3189
3168
|
'ai-inventory': 'Usage: npx thumbgate ai-inventory [--root <dir>] [--format=summary|json|cyclonedx] [--output <path>] [--max-files=N]\n\nScan source/manifests/model artifacts for AI, ML, agent-framework, vector DB, Vertex, Gemini, and Dialogflow CX components. Use --format=cyclonedx to produce exportable ML-BOM evidence for enterprise reviews.',
|
|
3190
3169
|
brain: 'Usage: npx thumbgate brain [--write] [--json] [--limit=N]\n\nBuild the agent-readable "context brain" — a single artifact consolidating this\nrepo\'s lessons, prevention rules, active gates, and project context for a coding\nagent to read BEFORE acting. --write saves it to .thumbgate/BRAIN.md (versioned,\ndeterministic). --json emits the structured model. --limit caps lessons (default 15).',
|
|
3191
3170
|
'team-sync': 'Usage: npx thumbgate team-sync\n\nSynchronize prevention rules and context brain with your team\'s git repository (git pull --rebase & git push), then auto-rebuild the local brain.',
|
|
3171
|
+
dream: 'Usage: npx thumbgate dream [--min=N] [--feedback-dir=DIR] [--json]\n\nConsolidate raw history and lessons ("Silicon Dreaming"), merge duplicates, promote recurring failures to gates, and rebuild prevention rules + BRAIN.md.',
|
|
3172
|
+
consolidate: 'Usage: npx thumbgate consolidate\n\nAlias for npx thumbgate dream.',
|
|
3173
|
+
triage: 'Usage: npx thumbgate triage [--schedule="daily 9:00"] [--json]\n\nRun git updates, test verification, and memory consolidation, or schedule it on a cron.',
|
|
3174
|
+
hygiene: 'Usage: npx thumbgate hygiene\n\nAlias for npx thumbgate triage.',
|
|
3175
|
+
community: 'Usage: npx thumbgate community query <error> | share <rule-id>\n\nQuery or share verified prevention rules with the community knowledge registry.',
|
|
3192
3176
|
};
|
|
3193
3177
|
|
|
3194
3178
|
if (_wantsHelp && COMMAND && SUBCOMMAND_HELP[COMMAND]) {
|
|
@@ -3291,6 +3275,31 @@ function renderBrainMarkdown(model) {
|
|
|
3291
3275
|
return out.join('\n');
|
|
3292
3276
|
}
|
|
3293
3277
|
|
|
3278
|
+
function autoWireInstructionFile(fileName) {
|
|
3279
|
+
const filePath = path.join(CWD, fileName);
|
|
3280
|
+
if (!fs.existsSync(filePath)) return;
|
|
3281
|
+
try {
|
|
3282
|
+
let content = fs.readFileSync(filePath, 'utf8');
|
|
3283
|
+
const blockStart = '<!-- ThumbGate -->';
|
|
3284
|
+
const blockEnd = '<!-- End ThumbGate -->';
|
|
3285
|
+
const block = `${blockStart}\nIMPORTANT: Read .thumbgate/BRAIN.md first for lessons, prevention rules, and active gates in this repo.\n${blockEnd}\n`;
|
|
3286
|
+
|
|
3287
|
+
if (content.includes(blockStart)) {
|
|
3288
|
+
const startIdx = content.indexOf(blockStart);
|
|
3289
|
+
const endIdx = content.indexOf(blockEnd);
|
|
3290
|
+
if (endIdx !== -1) {
|
|
3291
|
+
content = content.slice(0, startIdx) + block + content.slice(endIdx + blockEnd.length).replace(/^\n+/, '');
|
|
3292
|
+
}
|
|
3293
|
+
} else {
|
|
3294
|
+
content = block + '\n' + content;
|
|
3295
|
+
}
|
|
3296
|
+
fs.writeFileSync(filePath, content);
|
|
3297
|
+
console.error(` Auto-wired agent pointer into ${fileName}`);
|
|
3298
|
+
} catch (err) {
|
|
3299
|
+
console.warn(`⚠️ Failed to auto-wire agent pointer in ${fileName}: ${err.message}`);
|
|
3300
|
+
}
|
|
3301
|
+
}
|
|
3302
|
+
|
|
3294
3303
|
function cmdBrain(args = {}) {
|
|
3295
3304
|
const model = buildBrainModel({ limit: args.limit });
|
|
3296
3305
|
if (args.json) { console.log(JSON.stringify(model, null, 2)); return 0; }
|
|
@@ -3310,14 +3319,120 @@ function cmdBrain(args = {}) {
|
|
|
3310
3319
|
const lt = (model.lessons && model.lessons.total) || 0;
|
|
3311
3320
|
const rt = (model.rules && model.rules.total) || 0;
|
|
3312
3321
|
const gt = (model.gates && model.gates.total) || 0;
|
|
3313
|
-
console.
|
|
3314
|
-
|
|
3322
|
+
console.error(`\u{1f9e0} Wrote context brain to .thumbgate/BRAIN.md (${lt} lessons · ${rt} rules · ${gt} gates).`);
|
|
3323
|
+
|
|
3324
|
+
// Auto-inject pointer block into CLAUDE.md / AGENTS.md
|
|
3325
|
+
autoWireInstructionFile('CLAUDE.md');
|
|
3326
|
+
autoWireInstructionFile('AGENTS.md');
|
|
3327
|
+
|
|
3315
3328
|
return 0;
|
|
3316
3329
|
}
|
|
3317
3330
|
process.stdout.write(md);
|
|
3318
3331
|
return 0;
|
|
3319
3332
|
}
|
|
3320
3333
|
|
|
3334
|
+
function brain() {
|
|
3335
|
+
const args = parseArgs(process.argv.slice(3));
|
|
3336
|
+
const subcommand = process.argv.slice(3).find((arg) => !arg.startsWith('--')) || 'status';
|
|
3337
|
+
const {
|
|
3338
|
+
buildContextPack,
|
|
3339
|
+
checkNeverDo,
|
|
3340
|
+
cleanupReport,
|
|
3341
|
+
ensureBrain,
|
|
3342
|
+
formatContextPack,
|
|
3343
|
+
recordMemory,
|
|
3344
|
+
refreshNeverDoGates,
|
|
3345
|
+
} = require(path.join(PKG_ROOT, 'scripts', 'brain'));
|
|
3346
|
+
|
|
3347
|
+
if (subcommand === 'init' || subcommand === 'status') {
|
|
3348
|
+
const result = ensureBrain(CWD);
|
|
3349
|
+
const gates = refreshNeverDoGates(CWD);
|
|
3350
|
+
const payload = { ...result, gateCount: gates.gateCount };
|
|
3351
|
+
if (args.json) {
|
|
3352
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
3353
|
+
return;
|
|
3354
|
+
}
|
|
3355
|
+
console.log('ThumbGate brain');
|
|
3356
|
+
console.log('='.repeat(15));
|
|
3357
|
+
console.log(`Brain dir : ${path.relative(CWD, result.brainDir)}`);
|
|
3358
|
+
console.log(`Created : ${result.created.length}`);
|
|
3359
|
+
console.log(`Soul files: ${result.soulFiles.length}`);
|
|
3360
|
+
console.log(`Memory dirs: ${result.memoryDirs.length}`);
|
|
3361
|
+
console.log(`Never-do gates: ${gates.gateCount}`);
|
|
3362
|
+
return;
|
|
3363
|
+
}
|
|
3364
|
+
|
|
3365
|
+
if (subcommand === 'context') {
|
|
3366
|
+
const task = args.task || process.argv.slice(4).find((arg) => !arg.startsWith('--')) || '';
|
|
3367
|
+
const pack = buildContextPack(CWD, { task });
|
|
3368
|
+
if (args.json) {
|
|
3369
|
+
console.log(JSON.stringify(pack, null, 2));
|
|
3370
|
+
return;
|
|
3371
|
+
}
|
|
3372
|
+
process.stdout.write(formatContextPack(pack));
|
|
3373
|
+
return;
|
|
3374
|
+
}
|
|
3375
|
+
|
|
3376
|
+
if (subcommand === 'remember') {
|
|
3377
|
+
const title = args.title || process.argv.slice(4).find((arg) => !arg.startsWith('--')) || '';
|
|
3378
|
+
const result = recordMemory(CWD, {
|
|
3379
|
+
type: args.type,
|
|
3380
|
+
title,
|
|
3381
|
+
content: args.content || title,
|
|
3382
|
+
reason: args.reason,
|
|
3383
|
+
source: args.source,
|
|
3384
|
+
tags: args.tags,
|
|
3385
|
+
date: args.date,
|
|
3386
|
+
});
|
|
3387
|
+
if (args.json) {
|
|
3388
|
+
console.log(JSON.stringify(result, null, 2));
|
|
3389
|
+
return;
|
|
3390
|
+
}
|
|
3391
|
+
if (!result.ok) {
|
|
3392
|
+
console.error(result.error);
|
|
3393
|
+
process.exit(1);
|
|
3394
|
+
}
|
|
3395
|
+
console.log(`Stored brain memory: ${result.path}`);
|
|
3396
|
+
return;
|
|
3397
|
+
}
|
|
3398
|
+
|
|
3399
|
+
if (subcommand === 'check') {
|
|
3400
|
+
const text = args.text || args.action || readStdinText();
|
|
3401
|
+
const result = checkNeverDo(CWD, { text });
|
|
3402
|
+
if (args.json) {
|
|
3403
|
+
console.log(JSON.stringify(result, null, 2));
|
|
3404
|
+
if (!result.ok) process.exit(2);
|
|
3405
|
+
return;
|
|
3406
|
+
}
|
|
3407
|
+
console.log(`ThumbGate brain decision: ${result.decision.toUpperCase()}`);
|
|
3408
|
+
for (const rule of result.blocked) console.log(`- ${rule.text}`);
|
|
3409
|
+
if (!result.ok) process.exit(2);
|
|
3410
|
+
return;
|
|
3411
|
+
}
|
|
3412
|
+
|
|
3413
|
+
if (subcommand === 'cleanup') {
|
|
3414
|
+
const report = cleanupReport(CWD, args);
|
|
3415
|
+
if (args.json) {
|
|
3416
|
+
console.log(JSON.stringify(report, null, 2));
|
|
3417
|
+
return;
|
|
3418
|
+
}
|
|
3419
|
+
console.log('ThumbGate brain cleanup report');
|
|
3420
|
+
console.log('='.repeat(31));
|
|
3421
|
+
console.log(`Memory files: ${report.total}`);
|
|
3422
|
+
console.log(`Unsourced : ${report.unsourced.length}`);
|
|
3423
|
+
console.log(`Stale : ${report.stale.length}`);
|
|
3424
|
+
console.log(`Duplicates : ${report.duplicates.length}`);
|
|
3425
|
+
if (report.unsourced.length) {
|
|
3426
|
+
console.log('\nUnsourced files:');
|
|
3427
|
+
for (const filePath of report.unsourced) console.log(`- ${filePath}`);
|
|
3428
|
+
}
|
|
3429
|
+
return;
|
|
3430
|
+
}
|
|
3431
|
+
|
|
3432
|
+
console.error('Usage: npx thumbgate brain init|context|remember|check|cleanup [--json]');
|
|
3433
|
+
process.exit(1);
|
|
3434
|
+
}
|
|
3435
|
+
|
|
3321
3436
|
async function teamSync() {
|
|
3322
3437
|
const { execSync } = require('child_process');
|
|
3323
3438
|
|
|
@@ -3496,6 +3611,127 @@ switch (COMMAND) {
|
|
|
3496
3611
|
}
|
|
3497
3612
|
break;
|
|
3498
3613
|
}
|
|
3614
|
+
case 'dream':
|
|
3615
|
+
case 'consolidate': {
|
|
3616
|
+
const args = parseArgs(process.argv.slice(3));
|
|
3617
|
+
const { dream } = require(path.join(PKG_ROOT, 'scripts', 'dream-consolidation'));
|
|
3618
|
+
dream({
|
|
3619
|
+
pkgRoot: PKG_ROOT,
|
|
3620
|
+
feedbackDir: args['feedback-dir'] || args.feedbackDir || CWD,
|
|
3621
|
+
rulesPath: args.output || path.join(CWD, '.thumbgate', 'prevention-rules.md'),
|
|
3622
|
+
minOccurrences: args.min || 2,
|
|
3623
|
+
}).then(async (result) => {
|
|
3624
|
+
try {
|
|
3625
|
+
await cmdBrain({ write: true });
|
|
3626
|
+
} catch (brainErr) {
|
|
3627
|
+
console.warn(`⚠️ Failed to rebuild context brain: ${brainErr.message}`);
|
|
3628
|
+
}
|
|
3629
|
+
if (args.json) {
|
|
3630
|
+
console.log(JSON.stringify(result, null, 2));
|
|
3631
|
+
} else {
|
|
3632
|
+
console.log(`✨ [Dreaming] Consolidation complete! Merged ${result.consolidated} duplicate(s) into ${result.lessonsCount} lessons.`);
|
|
3633
|
+
}
|
|
3634
|
+
process.exit(0);
|
|
3635
|
+
}).catch((err) => {
|
|
3636
|
+
console.error('❌ Error during memory consolidation:', err && err.message ? err.message : err);
|
|
3637
|
+
process.exit(1);
|
|
3638
|
+
});
|
|
3639
|
+
break;
|
|
3640
|
+
}
|
|
3641
|
+
case 'triage':
|
|
3642
|
+
case 'hygiene': {
|
|
3643
|
+
const args = parseArgs(process.argv.slice(3));
|
|
3644
|
+
const { runTriageLoop } = require(path.join(PKG_ROOT, 'scripts', 'triage-loop'));
|
|
3645
|
+
|
|
3646
|
+
if (args.schedule) {
|
|
3647
|
+
const { createSchedule } = require(path.join(PKG_ROOT, 'scripts', 'schedule-manager'));
|
|
3648
|
+
const scheduleResult = createSchedule({
|
|
3649
|
+
id: 'thumbgate-triage-hygiene',
|
|
3650
|
+
name: 'ThumbGate Triage & Hygiene Loop',
|
|
3651
|
+
description: 'Run autonomous git checks, test suite verification, and Silicon Dreaming memory consolidation.',
|
|
3652
|
+
schedule: args.schedule,
|
|
3653
|
+
command: `const { runTriageLoop } = require('${path.join(PKG_ROOT, 'scripts', 'triage-loop')}'); runTriageLoop({ cwd: '${CWD}', pkgRoot: '${PKG_ROOT}' }).catch(console.error);`,
|
|
3654
|
+
workingDirectory: CWD,
|
|
3655
|
+
});
|
|
3656
|
+
if (args.json) {
|
|
3657
|
+
console.log(JSON.stringify(scheduleResult, null, 2));
|
|
3658
|
+
} else {
|
|
3659
|
+
if (scheduleResult.success) {
|
|
3660
|
+
console.log(`✅ [Triage] Scheduled triage hygiene loop: ${scheduleResult.message}`);
|
|
3661
|
+
} else {
|
|
3662
|
+
console.error(`❌ [Triage] Failed to schedule: ${scheduleResult.error}`);
|
|
3663
|
+
process.exit(1);
|
|
3664
|
+
}
|
|
3665
|
+
}
|
|
3666
|
+
break;
|
|
3667
|
+
}
|
|
3668
|
+
|
|
3669
|
+
runTriageLoop({
|
|
3670
|
+
cwd: CWD,
|
|
3671
|
+
pkgRoot: PKG_ROOT,
|
|
3672
|
+
}).then(async (result) => {
|
|
3673
|
+
try {
|
|
3674
|
+
await cmdBrain({ write: true });
|
|
3675
|
+
} catch (brainErr) {
|
|
3676
|
+
console.warn(`⚠️ Failed to rebuild context brain: ${brainErr.message}`);
|
|
3677
|
+
}
|
|
3678
|
+
if (args.json) {
|
|
3679
|
+
console.log(JSON.stringify(result, null, 2));
|
|
3680
|
+
} else {
|
|
3681
|
+
console.log(result.log);
|
|
3682
|
+
}
|
|
3683
|
+
process.exit(0);
|
|
3684
|
+
}).catch((err) => {
|
|
3685
|
+
console.error('❌ Error during triage loop execution:', err && err.message ? err.message : err);
|
|
3686
|
+
process.exit(1);
|
|
3687
|
+
});
|
|
3688
|
+
break;
|
|
3689
|
+
}
|
|
3690
|
+
case 'community': {
|
|
3691
|
+
const args = parseArgs(process.argv.slice(3));
|
|
3692
|
+
const sub = process.argv.slice(3).find((arg) => !arg.startsWith('--'));
|
|
3693
|
+
const { queryCommunity, shareRule } = require(path.join(PKG_ROOT, 'scripts', 'community-knowledge'));
|
|
3694
|
+
|
|
3695
|
+
if (sub === 'query') {
|
|
3696
|
+
const queryIdx = process.argv.indexOf('query');
|
|
3697
|
+
const queryText = process.argv.slice(queryIdx + 1).filter(arg => !arg.startsWith('--')).join(' ');
|
|
3698
|
+
const result = queryCommunity(queryText, { remote: args.remote });
|
|
3699
|
+
if (args.json) {
|
|
3700
|
+
console.log(JSON.stringify(result, null, 2));
|
|
3701
|
+
} else {
|
|
3702
|
+
console.log(`🔍 Found ${result.resultsCount} community rule(s) matching "${result.query}":`);
|
|
3703
|
+
for (const r of result.results) {
|
|
3704
|
+
console.log(`\n- [${r.id}] ${r.rule}`);
|
|
3705
|
+
console.log(` Remedy: ${r.remedy}`);
|
|
3706
|
+
console.log(` Explanation: ${r.explanation}`);
|
|
3707
|
+
}
|
|
3708
|
+
}
|
|
3709
|
+
process.exit(0);
|
|
3710
|
+
} else if (sub === 'share') {
|
|
3711
|
+
const shareIdx = process.argv.indexOf('share');
|
|
3712
|
+
const ruleId = process.argv.slice(shareIdx + 1).find(arg => !arg.startsWith('--'));
|
|
3713
|
+
if (!ruleId) {
|
|
3714
|
+
console.error('❌ Error: rule ID is required for share subcommand.');
|
|
3715
|
+
process.exit(1);
|
|
3716
|
+
}
|
|
3717
|
+
const result = shareRule(ruleId, { feedbackDir: CWD });
|
|
3718
|
+
if (args.json) {
|
|
3719
|
+
console.log(JSON.stringify(result, null, 2));
|
|
3720
|
+
} else {
|
|
3721
|
+
if (result.ok) {
|
|
3722
|
+
console.log(`✨ Successfully shared rule "${ruleId}" to community registry.`);
|
|
3723
|
+
} else {
|
|
3724
|
+
console.error(`❌ Failed to share rule: ${result.error}`);
|
|
3725
|
+
process.exit(1);
|
|
3726
|
+
}
|
|
3727
|
+
}
|
|
3728
|
+
process.exit(0);
|
|
3729
|
+
} else {
|
|
3730
|
+
console.error('Usage: npx thumbgate community query <error> | share <rule-id> [--json]');
|
|
3731
|
+
process.exit(1);
|
|
3732
|
+
}
|
|
3733
|
+
break;
|
|
3734
|
+
}
|
|
3499
3735
|
case 'billing:setup':
|
|
3500
3736
|
require(path.join(PKG_ROOT, 'scripts', 'billing-setup'));
|
|
3501
3737
|
break;
|
|
@@ -3863,14 +4099,6 @@ switch (COMMAND) {
|
|
|
3863
4099
|
case 'pulse':
|
|
3864
4100
|
pulse();
|
|
3865
4101
|
break;
|
|
3866
|
-
case 'check-update':
|
|
3867
|
-
case 'upgrade-check':
|
|
3868
|
-
checkUpdateCmd();
|
|
3869
|
-
break;
|
|
3870
|
-
case 'self-update':
|
|
3871
|
-
case 'upgrade-cli':
|
|
3872
|
-
selfUpdateCmd();
|
|
3873
|
-
break;
|
|
3874
4102
|
case 'dispatch':
|
|
3875
4103
|
case 'dispatch-brief':
|
|
3876
4104
|
dispatchBrief();
|
|
@@ -3896,53 +4124,6 @@ switch (COMMAND) {
|
|
|
3896
4124
|
});
|
|
3897
4125
|
break;
|
|
3898
4126
|
}
|
|
3899
|
-
case 'hermes-gate': {
|
|
3900
|
-
// Nous Research Hermes Agent `pre_tool_call` shell hook.
|
|
3901
|
-
// Hermes pipes each pending tool call as JSON to stdin and reads a decision from stdout;
|
|
3902
|
-
// {"decision":"block","reason":...} vetoes the call. We reuse the SAME gate pipeline as
|
|
3903
|
-
// `gate-check` (runAsync → secret guard, security scan, force-push / skill_manage / learned
|
|
3904
|
-
// prevention rules) and translate the verdict into Hermes's format.
|
|
3905
|
-
//
|
|
3906
|
-
// Hermes `pre_tool_call` is binary (block or allow) with no warn channel, and the whole point
|
|
3907
|
-
// of wiring it is to gate, so we run STRICT enforcement by default — otherwise ThumbGate's
|
|
3908
|
-
// warn-by-default posture would pass every deny through and the hook would block nothing.
|
|
3909
|
-
// Opt out with THUMBGATE_HERMES_WARN_ONLY=1; THUMBGATE_HOTFIX_BYPASS=1 still disables checks.
|
|
3910
|
-
// Wire it in ~/.hermes/config.yaml — see adapters/hermes/config.yaml.
|
|
3911
|
-
if (process.env.THUMBGATE_HERMES_WARN_ONLY !== '1' && process.env.THUMBGATE_HOTFIX_BYPASS !== '1') {
|
|
3912
|
-
process.env.THUMBGATE_STRICT_ENFORCEMENT = '1';
|
|
3913
|
-
}
|
|
3914
|
-
const { runAsync: hermesGateRun } = require(path.join(PKG_ROOT, 'scripts', 'gates-engine'));
|
|
3915
|
-
let hermesStdin = '';
|
|
3916
|
-
process.stdin.setEncoding('utf8');
|
|
3917
|
-
process.stdin.on('data', (chunk) => { hermesStdin += chunk; });
|
|
3918
|
-
process.stdin.on('end', async () => {
|
|
3919
|
-
try {
|
|
3920
|
-
const payload = JSON.parse(hermesStdin);
|
|
3921
|
-
// Hermes sends snake_case tool_name/tool_input — gates-engine reads these directly.
|
|
3922
|
-
const verdict = await hermesGateRun({ tool_name: payload.tool_name, tool_input: payload.tool_input });
|
|
3923
|
-
let parsed = {};
|
|
3924
|
-
try { parsed = JSON.parse(verdict); } catch (_e) { parsed = {}; }
|
|
3925
|
-
const hso = parsed.hookSpecificOutput || {};
|
|
3926
|
-
if (hso.permissionDecision === 'deny') {
|
|
3927
|
-
process.stdout.write(JSON.stringify({
|
|
3928
|
-
decision: 'block',
|
|
3929
|
-
reason: hso.permissionDecisionReason || 'Blocked by ThumbGate prevention rule.',
|
|
3930
|
-
}) + '\n');
|
|
3931
|
-
} else {
|
|
3932
|
-
// warn / no match → allow. The gate engine already logged the decision.
|
|
3933
|
-
process.stdout.write(JSON.stringify({}) + '\n');
|
|
3934
|
-
}
|
|
3935
|
-
process.exit(0);
|
|
3936
|
-
} catch (err) {
|
|
3937
|
-
// Hermes hooks fail OPEN on error/timeout — emit an explicit allow so a gate fault
|
|
3938
|
-
// never wedges the agent (reliability ≈ enforcement; keep this fast).
|
|
3939
|
-
process.stderr.write(`hermes-gate error: ${err.message}\n`);
|
|
3940
|
-
process.stdout.write(JSON.stringify({}) + '\n');
|
|
3941
|
-
process.exit(0);
|
|
3942
|
-
}
|
|
3943
|
-
});
|
|
3944
|
-
break;
|
|
3945
|
-
}
|
|
3946
4127
|
case 'gate-stats':
|
|
3947
4128
|
gateStats();
|
|
3948
4129
|
break;
|