thumbgate 1.27.11 → 1.27.13
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 +2 -1
- package/.well-known/mcp/server-card.json +1 -1
- package/README.md +2 -4
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/mcp/server-stdio.js +1 -1
- package/adapters/opencode/opencode.json +1 -1
- package/adapters/policy-engine/ethicore-guardian-client.js +68 -0
- package/adapters/policy-engine/thumbgate-policy-engine-adapter.js +260 -0
- package/bin/cli.js +78 -259
- package/config/builtin-lessons.json +23 -0
- package/config/gate-templates.json +0 -228
- package/config/gates/claim-verification.json +0 -18
- package/package.json +35 -25
- package/public/assets/brand/thumbgate-logo-transparent.svg +22 -0
- package/public/assets/brand/thumbgate-mark-inline-v3.svg +19 -0
- package/public/assets/brand/thumbgate-mark.svg +11 -5
- package/public/blog.html +0 -30
- package/public/brand/thumbgate-mark.svg +9 -5
- package/public/chatgpt-app.html +2 -2
- package/public/compare.html +2 -1
- package/public/dashboard.html +1 -1
- package/public/federal.html +1 -1
- package/public/index.html +95 -216
- package/public/learn.html +59 -35
- package/public/lessons.html +1 -1
- package/public/numbers.html +2 -2
- package/public/pro.html +7 -7
- package/scripts/aws-blocks-guardrails.js +228 -0
- package/scripts/cli-schema.js +22 -10
- package/scripts/dashboard-chat.js +2 -1
- package/scripts/document-intake.js +1 -49
- package/scripts/durability/step.js +3 -3
- package/scripts/gate-stats.js +5 -11
- package/scripts/gemini-embedding-policy.js +2 -1
- package/scripts/hook-stop-anti-claim.js +116 -184
- package/scripts/hosted-config.js +0 -12
- package/scripts/llm-client.js +187 -5
- package/scripts/plausible-domain-config.js +3 -1
- package/scripts/seo-gsd.js +240 -1
- package/scripts/tool-registry.js +2 -2
- package/scripts/vector-store.js +44 -0
- package/scripts/workspace-evolver.js +62 -2
- package/src/api/server.js +340 -131
- package/public/assets/brand/thumbgate-mark-inline.svg +0 -15
- package/public/compare/adopt-ai.html +0 -219
- package/public/compare/agentix-labs.html +0 -197
- package/public/compare/ai-experience-orchestration.html +0 -216
- package/public/compare/anthropic-claude-for-legal.html +0 -260
- package/public/compare/anthropic-containment.html +0 -280
- package/public/compare/arcade.html +0 -175
- package/public/compare/arcjet.html +0 -239
- package/public/compare/bumblebee.html +0 -307
- package/public/compare/claude-code-hooks.html +0 -294
- package/public/compare/databricks-unity-ai-gateway.html +0 -215
- package/public/compare/fallow.html +0 -351
- package/public/compare/heidi.html +0 -233
- package/public/compare/mem0.html +0 -342
- package/public/compare/oak-and-sparrow-gatekeeper.html +0 -289
- package/public/compare/rein.html +0 -236
- package/public/compare/sigmashake.html +0 -256
- package/public/compare/speclock.html +0 -342
- package/public/guides/agent-harness-optimization.html +0 -342
- package/public/guides/agentic-web-governance.html +0 -406
- package/public/guides/ai-agent-governance-sprint.html +0 -415
- package/public/guides/ai-agent-pre-action-approval-gates.html +0 -401
- package/public/guides/ai-agent-workflow-migration-checklist.html +0 -392
- package/public/guides/ai-deployment-readiness.html +0 -415
- package/public/guides/ai-mode-ads-agent-governance.html +0 -401
- package/public/guides/ai-search-topical-presence.html +0 -342
- package/public/guides/autoresearch-agent-safety.html +0 -342
- package/public/guides/background-agent-governance.html +0 -358
- package/public/guides/best-tools-stop-ai-agents-breaking-production.html +0 -363
- package/public/guides/browser-automation-safety.html +0 -342
- package/public/guides/chatgpt-ads-trust.html +0 -353
- package/public/guides/claude-code-feedback.html +0 -339
- package/public/guides/claude-code-prevent-repeated-mistakes.html +0 -161
- package/public/guides/claude-code-skills-guardrails.html +0 -343
- package/public/guides/claude-desktop.html +0 -356
- package/public/guides/code-knowledge-graph-guardrails.html +0 -365
- package/public/guides/codex-cli-guardrails.html +0 -339
- package/public/guides/cursor-agent-guardrails.html +0 -339
- package/public/guides/cursor-prevent-repeated-mistakes.html +0 -161
- package/public/guides/database-agent-safety.html +0 -406
- package/public/guides/deepseek-v4-runtime-guardrails.html +0 -346
- package/public/guides/developer-machine-supply-chain-guardrails.html +0 -358
- package/public/guides/gcp-mcp-guardrails.html +0 -147
- package/public/guides/gemini-cli-feedback-memory.html +0 -339
- package/public/guides/gpt-5-5-model-evaluation.html +0 -358
- package/public/guides/internal-ai-engineering-stack-guardrails.html +0 -348
- package/public/guides/long-running-agent-context-management.html +0 -346
- package/public/guides/mcp-tool-governance.html +0 -401
- package/public/guides/multica-thumbgate-setup.html +0 -134
- package/public/guides/native-messaging-host-security.html +0 -342
- package/public/guides/policy-engine-pre-action-gates.html +0 -346
- package/public/guides/pre-action-checks.html +0 -342
- package/public/guides/pretooluse-hooks-vs-advisory-prompt-rules.html +0 -342
- package/public/guides/prompt-tricks-to-workflow-rules.html +0 -365
- package/public/guides/proxy-pointer-rag-guardrails.html +0 -352
- package/public/guides/rag-precision-tuning-guardrails.html +0 -352
- package/public/guides/reasoning-compression-guardrails.html +0 -346
- package/public/guides/relational-knowledge-ai-recommendations.html +0 -342
- package/public/guides/roo-code-alternative-cline.html +0 -339
- package/public/guides/semantic-programmatic-seo-guardrails.html +0 -352
- package/public/guides/seo-agent-skills-guardrails.html +0 -344
- package/public/guides/stop-repeated-ai-agent-mistakes.html +0 -342
- package/public/learn/ac-dc-runtime-enforcement.html +0 -277
- package/public/learn/agent-harness-pattern.html +0 -181
- package/public/learn/agent-identity-connector-governance.html +0 -146
- package/public/learn/agent-swarms-shared-gates.html +0 -173
- package/public/learn/agentic-enterprise-context-brain.html +0 -117
- package/public/learn/agentic-os-team-governance.html +0 -146
- package/public/learn/ai-agent-governance.html +0 -158
- package/public/learn/ai-agent-persistent-memory.html +0 -211
- package/public/learn/anthropomorphic-claim-gates.html +0 -180
- package/public/learn/background-agent-control-layer.html +0 -184
- package/public/learn/claude-code-goal-with-rubrics.html +0 -205
- package/public/learn/codex-role-plugins-need-governance.html +0 -125
- package/public/learn/cost-aware-agent-gate-routing.html +0 -173
- package/public/learn/databricks-unity-ai-gateway-runtime-governance.html +0 -157
- package/public/learn/deterministic-agent-workflows.html +0 -185
- package/public/learn/feedback-loop-vs-decision-layer.html +0 -283
- package/public/learn/from-prototype-to-production.html +0 -223
- package/public/learn/learn.css +0 -51
- package/public/learn/mcp-pre-action-checks-explained.html +0 -172
- package/public/learn/pretix-stripe-connect-marketplaces.html +0 -161
- package/public/learn/regulated-agent-execution-boundary.html +0 -196
- package/public/learn/spec-driven-development.html +0 -168
- package/public/learn/stop-ai-agent-force-push.html +0 -134
- package/public/learn/vibe-coding-safety-net.html +0 -142
- package/scripts/reddit-browser-notification-watch.js +0 -230
package/bin/cli.js
CHANGED
|
@@ -2188,6 +2188,26 @@ 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
|
+
|
|
2191
2211
|
function dispatchBrief() {
|
|
2192
2212
|
const args = parseArgs(process.argv.slice(3));
|
|
2193
2213
|
const {
|
|
@@ -3151,6 +3171,7 @@ const SUBCOMMAND_HELP = {
|
|
|
3151
3171
|
lessons: 'Usage: npx thumbgate lessons [--query="..."] [--limit=N]\n\nSearch the lesson database (Pro feature).',
|
|
3152
3172
|
search: 'Usage: npx thumbgate search <query>\n\nSearch ThumbGate knowledge base (Pro feature).',
|
|
3153
3173
|
'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.',
|
|
3154
3175
|
'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.',
|
|
3155
3176
|
serve: 'Usage: npx thumbgate serve\n\nStart the MCP stdio server. This is for agent runtimes, not the local HTTP dashboard.',
|
|
3156
3177
|
mcp: 'Usage: npx thumbgate mcp\n\nAlias for `thumbgate serve`.',
|
|
@@ -3168,11 +3189,6 @@ const SUBCOMMAND_HELP = {
|
|
|
3168
3189
|
'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.',
|
|
3169
3190
|
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).',
|
|
3170
3191
|
'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.',
|
|
3176
3192
|
};
|
|
3177
3193
|
|
|
3178
3194
|
if (_wantsHelp && COMMAND && SUBCOMMAND_HELP[COMMAND]) {
|
|
@@ -3275,31 +3291,6 @@ function renderBrainMarkdown(model) {
|
|
|
3275
3291
|
return out.join('\n');
|
|
3276
3292
|
}
|
|
3277
3293
|
|
|
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
|
-
|
|
3303
3294
|
function cmdBrain(args = {}) {
|
|
3304
3295
|
const model = buildBrainModel({ limit: args.limit });
|
|
3305
3296
|
if (args.json) { console.log(JSON.stringify(model, null, 2)); return 0; }
|
|
@@ -3319,120 +3310,14 @@ function cmdBrain(args = {}) {
|
|
|
3319
3310
|
const lt = (model.lessons && model.lessons.total) || 0;
|
|
3320
3311
|
const rt = (model.rules && model.rules.total) || 0;
|
|
3321
3312
|
const gt = (model.gates && model.gates.total) || 0;
|
|
3322
|
-
console.
|
|
3323
|
-
|
|
3324
|
-
// Auto-inject pointer block into CLAUDE.md / AGENTS.md
|
|
3325
|
-
autoWireInstructionFile('CLAUDE.md');
|
|
3326
|
-
autoWireInstructionFile('AGENTS.md');
|
|
3327
|
-
|
|
3313
|
+
console.log(`\u{1f9e0} Wrote context brain to .thumbgate/BRAIN.md (${lt} lessons · ${rt} rules · ${gt} gates).`);
|
|
3314
|
+
console.log(' Point your agent at it: add "Read .thumbgate/BRAIN.md first" to CLAUDE.md / AGENTS.md.');
|
|
3328
3315
|
return 0;
|
|
3329
3316
|
}
|
|
3330
3317
|
process.stdout.write(md);
|
|
3331
3318
|
return 0;
|
|
3332
3319
|
}
|
|
3333
3320
|
|
|
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
|
-
|
|
3436
3321
|
async function teamSync() {
|
|
3437
3322
|
const { execSync } = require('child_process');
|
|
3438
3323
|
|
|
@@ -3611,127 +3496,6 @@ switch (COMMAND) {
|
|
|
3611
3496
|
}
|
|
3612
3497
|
break;
|
|
3613
3498
|
}
|
|
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
|
-
}
|
|
3735
3499
|
case 'billing:setup':
|
|
3736
3500
|
require(path.join(PKG_ROOT, 'scripts', 'billing-setup'));
|
|
3737
3501
|
break;
|
|
@@ -4099,6 +3863,14 @@ switch (COMMAND) {
|
|
|
4099
3863
|
case 'pulse':
|
|
4100
3864
|
pulse();
|
|
4101
3865
|
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;
|
|
4102
3874
|
case 'dispatch':
|
|
4103
3875
|
case 'dispatch-brief':
|
|
4104
3876
|
dispatchBrief();
|
|
@@ -4124,6 +3896,53 @@ switch (COMMAND) {
|
|
|
4124
3896
|
});
|
|
4125
3897
|
break;
|
|
4126
3898
|
}
|
|
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
|
+
}
|
|
4127
3946
|
case 'gate-stats':
|
|
4128
3947
|
gateStats();
|
|
4129
3948
|
break;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"lessons": [
|
|
4
|
+
{
|
|
5
|
+
"id": "builtin-response-quality-shallow-positive-closeout",
|
|
6
|
+
"title": "MISTAKE: Assistant gave shallow acknowledgement after user said thumbs up",
|
|
7
|
+
"content": "What went wrong: Assistant gave shallow acknowledgement after positive feedback, such as thumbs up, perfect, good, or thank you, instead of staying quiet or giving an evidence checkpoint.\nHow to avoid: If the previous user message is positive feedback and the proposed final response is a low-value social closeout, block it and require either silence-level brevity or a compact evidence checkpoint with proof, result, residual risk, and next state.\nAction needed: Enforce this at the final-response boundary, not only as PreToolUse context.\nReasoning: Stored lessons and retrieval are not enough when the model can still ignore the lesson at generation time.",
|
|
8
|
+
"category": "error",
|
|
9
|
+
"importance": "high",
|
|
10
|
+
"tags": [
|
|
11
|
+
"feedback",
|
|
12
|
+
"negative",
|
|
13
|
+
"response-quality",
|
|
14
|
+
"final-response",
|
|
15
|
+
"positive-feedback",
|
|
16
|
+
"shallow-closeout",
|
|
17
|
+
"enforcement"
|
|
18
|
+
],
|
|
19
|
+
"timestamp": "2026-06-20T19:01:58.000Z",
|
|
20
|
+
"source": "packaged-builtin"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|