thumbgate 1.27.16 → 1.27.18
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 +85 -0
- package/.claude-plugin/plugin.json +3 -4
- package/.well-known/llms.txt +12 -33
- package/.well-known/mcp/server-card.json +8 -8
- package/README.md +30 -215
- package/adapters/chatgpt/openapi.yaml +1695 -0
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/gemini/function-declarations.json +0 -1
- package/adapters/mcp/server-stdio.js +11 -263
- package/adapters/opencode/opencode.json +1 -1
- package/bench/thumbgate-bench.json +2 -2
- package/bin/cli.js +122 -1421
- package/bin/postinstall.js +27 -11
- package/config/gate-templates.json +0 -216
- package/config/gates/claim-verification.json +0 -12
- package/config/gates/default.json +2 -31
- package/config/github-about.json +2 -2
- package/config/mcp-allowlists.json +13 -23
- package/config/merge-quality-checks.json +1 -0
- package/config/model-candidates.json +6 -121
- package/openapi/openapi.yaml +0 -12
- package/package.json +98 -228
- package/public/blog.html +4 -4
- package/public/codex-plugin.html +20 -72
- package/public/compare.html +8 -31
- package/public/dashboard.html +166 -930
- package/public/federal.html +2 -2
- package/public/guide.html +9 -33
- package/public/index.html +116 -495
- package/public/learn.html +18 -191
- package/public/lessons.html +10 -168
- package/public/numbers.html +7 -7
- package/public/pro.html +11 -34
- package/scripts/agent-memory-lifecycle.js +0 -211
- package/scripts/agent-readiness.js +3 -167
- package/scripts/agent-reward-model.js +1 -53
- package/scripts/auto-promote-gates.js +10 -82
- package/scripts/auto-wire-hooks.js +0 -14
- package/scripts/billing.js +1 -93
- package/scripts/build-metadata.js +10 -50
- package/scripts/cli-feedback.js +6 -18
- package/scripts/cli-schema.js +0 -90
- package/scripts/cli-telemetry.js +1 -6
- package/scripts/commercial-offer.js +2 -82
- package/scripts/context-manager.js +6 -74
- package/scripts/dashboard.js +2 -68
- package/scripts/durability/step.js +3 -3
- package/scripts/export-databricks-bundle.js +1 -5
- package/scripts/export-dpo-pairs.js +2 -7
- package/scripts/feedback-loop.js +1 -123
- package/scripts/feedback-quality.js +0 -87
- package/scripts/filesystem-search.js +10 -35
- package/scripts/gate-stats.js +0 -89
- package/scripts/gates-engine.js +85 -1105
- package/scripts/gemini-embedding-policy.js +1 -2
- package/scripts/hook-runtime.js +14 -20
- package/scripts/hook-thumbgate-cache-updater.js +2 -18
- package/scripts/hybrid-feedback-context.js +7 -142
- package/scripts/lesson-inference.js +3 -8
- package/scripts/lesson-search.js +1 -17
- package/scripts/license.js +1 -0
- package/scripts/llm-client.js +9 -390
- package/scripts/local-model-profile.js +8 -15
- package/scripts/memory-scope-readiness.js +0 -159
- package/scripts/meta-agent-loop.js +0 -36
- package/scripts/operational-integrity.js +5 -39
- package/scripts/oss-pr-opportunity-scout.js +5 -35
- package/scripts/plausible-server-events.js +6 -9
- package/scripts/pro-local-dashboard.js +4 -4
- package/scripts/proxy-pointer-rag-guardrails.js +1 -42
- package/scripts/rate-limiter.js +13 -64
- package/scripts/secret-scanner.js +5 -44
- package/scripts/security-scanner.js +10 -260
- package/scripts/self-distill-agent.js +1 -3
- package/scripts/seo-gsd.js +2 -916
- package/scripts/statusline-cache-path.js +2 -17
- package/scripts/statusline-local-stats.js +1 -9
- package/scripts/statusline-meta.js +2 -28
- package/scripts/statusline.sh +4 -20
- package/scripts/telemetry-analytics.js +0 -357
- package/scripts/thompson-sampling.js +10 -31
- package/scripts/thumbgate-bench.js +1 -16
- package/scripts/thumbgate-search.js +19 -85
- package/scripts/tool-registry.js +1 -169
- package/scripts/vector-store.js +0 -45
- package/scripts/workflow-sentinel.js +53 -286
- package/scripts/workspace-evolver.js +2 -62
- package/src/api/server.js +290 -2578
- package/.claude/commands/dashboard.md +0 -15
- package/.claude/commands/thumbgate-blocked.md +0 -27
- package/.claude/commands/thumbgate-dashboard.md +0 -15
- package/.claude/commands/thumbgate-doctor.md +0 -30
- package/.claude/commands/thumbgate-guard.md +0 -36
- package/.claude/commands/thumbgate-protect.md +0 -30
- package/.claude/commands/thumbgate-rules.md +0 -30
- package/.well-known/agentic-verify.txt +0 -1
- package/adapters/gcp/dfcx-webhook-gate.js +0 -295
- package/adapters/letta/README.md +0 -41
- package/adapters/letta/thumbgate-letta-adapter.js +0 -133
- package/adapters/policy-engine/ethicore-guardian-client.js +0 -68
- package/adapters/policy-engine/thumbgate-policy-engine-adapter.js +0 -260
- package/bench/observability-eval-suite.json +0 -26
- package/bin/dashboard-cli.js +0 -7
- package/commands/dashboard.md +0 -15
- package/commands/thumbgate-dashboard.md +0 -15
- package/config/builtin-lessons.json +0 -23
- package/config/gate-classifier-routing.json +0 -98
- package/config/post-deploy-marketing-pages.json +0 -61
- package/public/about.html +0 -162
- package/public/agent-manager.html +0 -179
- package/public/agents-cost-savings.html +0 -153
- package/public/ai-malpractice-prevention.html +0 -818
- package/public/assets/brand/github-social-preview.png +0 -0
- package/public/assets/brand/thumbgate-icon-512.png +0 -0
- package/public/assets/brand/thumbgate-icon-pro-512.png +0 -0
- package/public/assets/brand/thumbgate-icon-team-512.png +0 -0
- package/public/assets/brand/thumbgate-logo-1200x360.png +0 -0
- package/public/assets/brand/thumbgate-logo-transparent.svg +0 -22
- package/public/assets/brand/thumbgate-mark-inline-v3.svg +0 -19
- package/public/assets/brand/thumbgate-mark-pro.svg +0 -23
- package/public/assets/brand/thumbgate-mark-team.svg +0 -26
- package/public/assets/brand/thumbgate-mark.svg +0 -21
- package/public/assets/brand/thumbgate-wordmark.svg +0 -20
- package/public/assets/claude-thumbgate-statusbar.svg +0 -8
- package/public/assets/codex-thumbgate-statusbar-test.svg +0 -9
- package/public/assets/legal-intake-control-flow.svg +0 -66
- package/public/brand/thumbgate-mark.svg +0 -19
- package/public/brand/thumbgate-og.svg +0 -16
- package/public/chatgpt-app.html +0 -330
- package/public/codex-enterprise.html +0 -123
- package/public/js/buyer-intent.js +0 -672
- package/public/pricing.html +0 -399
- package/scripts/action-receipts.js +0 -324
- package/scripts/activation-quickstart.js +0 -187
- package/scripts/agent-operations-planner.js +0 -621
- package/scripts/ai-component-inventory.js +0 -367
- package/scripts/async-eval-observability.js +0 -236
- package/scripts/audit.js +0 -65
- package/scripts/aws-blocks-guardrails.js +0 -228
- package/scripts/classifier-routing.js +0 -130
- package/scripts/dashboard-chat.js +0 -332
- package/scripts/feedback-aggregate.js +0 -281
- package/scripts/feedback-sanitizer.js +0 -105
- package/scripts/hob-pack.js +0 -591
- package/scripts/hook-stop-anti-claim.js +0 -301
- package/scripts/install-shim.js +0 -87
- package/scripts/mcp-oauth.js +0 -293
- package/scripts/noop-detect.js +0 -285
- package/scripts/omlx-smoke.js +0 -192
- package/scripts/parallel-workflow-orchestrator.js +0 -293
- package/scripts/plan-gate.js +0 -243
- package/scripts/plausible-domain-config.js +0 -99
- package/scripts/qa-scenario-planner.js +0 -136
- package/scripts/repeat-metric.js +0 -137
- package/scripts/secret-fixture-tokens.js +0 -61
- package/scripts/secret-redaction.js +0 -166
- package/scripts/self-harness-optimizer.js +0 -141
- package/scripts/self-healing-check.js +0 -193
- package/scripts/silent-failure-cluster.js +0 -531
- package/scripts/statusline-cache-read.js +0 -57
- package/scripts/sync-telemetry-from-prod.js +0 -374
- package/scripts/tool-contract-validator.js +0 -76
- package/scripts/trajectory-scorer.js +0 -63
- package/scripts/verify-marketing-pages-deployed.js +0 -195
- package/scripts/visitor-journey.js +0 -172
|
@@ -122,7 +122,7 @@ function resolveGeminiEmbeddingConfig(env = process.env) {
|
|
|
122
122
|
|
|
123
123
|
return {
|
|
124
124
|
enabled,
|
|
125
|
-
provider:
|
|
125
|
+
provider: enabled ? 'gemini' : 'local',
|
|
126
126
|
model: String(env.THUMBGATE_GEMINI_EMBED_MODEL || GEMINI_EMBEDDING_2_MODEL).trim() || GEMINI_EMBEDDING_2_MODEL,
|
|
127
127
|
apiKey,
|
|
128
128
|
apiBaseUrl: trimTrailingSlashes(env.THUMBGATE_GEMINI_API_BASE_URL || 'https://generativelanguage.googleapis.com/v1beta'),
|
|
@@ -171,7 +171,6 @@ function buildGeminiEmbeddingRolloutPlan(args = {}) {
|
|
|
171
171
|
},
|
|
172
172
|
rolloutSteps: [
|
|
173
173
|
'Keep local embeddings as the default offline path.',
|
|
174
|
-
'For Apple Silicon developers, route local queries through Core AI (AOT compiled models) to bypass CPU overhead.',
|
|
175
174
|
'Enable Gemini Embedding 2 only when a Gemini API key is present.',
|
|
176
175
|
'Use task-specific query/document prefixes at index and retrieval time.',
|
|
177
176
|
'Start at 768 dimensions, then benchmark 1536 only if recall misses show up.',
|
package/scripts/hook-runtime.js
CHANGED
|
@@ -7,7 +7,6 @@ const {
|
|
|
7
7
|
publishedCliAvailable,
|
|
8
8
|
} = require('./mcp-config');
|
|
9
9
|
const { publishedCliShellCommand } = require('./published-cli');
|
|
10
|
-
const { shimInstalled, shimPath } = require('./install-shim');
|
|
11
10
|
|
|
12
11
|
const PKG_ROOT = path.join(__dirname, '..');
|
|
13
12
|
const featureSupportCache = new Map();
|
|
@@ -34,39 +33,34 @@ function publishedHookCommandsAvailable(version) {
|
|
|
34
33
|
return available;
|
|
35
34
|
}
|
|
36
35
|
|
|
37
|
-
function
|
|
38
|
-
// Source checkout: always use direct node command for development
|
|
39
|
-
if (isSourceCheckout(PKG_ROOT)) {
|
|
40
|
-
return `node ${shellQuote(path.join(PKG_ROOT, 'bin', 'cli.js'))} ${subcommand}`;
|
|
41
|
-
}
|
|
42
|
-
// Prefer stable shim — always resolves @latest, survives version bumps
|
|
43
|
-
if (shimInstalled()) {
|
|
44
|
-
return `${shellQuote(shimPath())} ${subcommand}`;
|
|
45
|
-
}
|
|
36
|
+
function resolveCliBaseCommand() {
|
|
46
37
|
const version = packageVersion();
|
|
47
38
|
if (publishedHookCommandsAvailable(version)) {
|
|
48
|
-
return publishedCliShellCommand(version
|
|
39
|
+
return publishedCliShellCommand(version);
|
|
40
|
+
}
|
|
41
|
+
if (isSourceCheckout(PKG_ROOT)) {
|
|
42
|
+
return `node ${shellQuote(path.join(PKG_ROOT, 'bin', 'cli.js'))}`;
|
|
49
43
|
}
|
|
50
|
-
return publishedCliShellCommand(version
|
|
44
|
+
return publishedCliShellCommand(version);
|
|
51
45
|
}
|
|
52
46
|
|
|
53
|
-
function
|
|
47
|
+
function resolveCodexCliBaseCommand() {
|
|
54
48
|
const version = packageVersion();
|
|
55
49
|
if (publishedHookCommandsAvailable(version)) {
|
|
56
|
-
return publishedCliShellCommand('latest', [
|
|
50
|
+
return publishedCliShellCommand('latest', [], { preferInstalled: false });
|
|
57
51
|
}
|
|
58
52
|
if (isSourceCheckout(PKG_ROOT)) {
|
|
59
|
-
return `node ${shellQuote(path.join(PKG_ROOT, 'bin', 'cli.js'))}
|
|
53
|
+
return `node ${shellQuote(path.join(PKG_ROOT, 'bin', 'cli.js'))}`;
|
|
60
54
|
}
|
|
61
|
-
return publishedCliShellCommand('latest', [
|
|
55
|
+
return publishedCliShellCommand('latest', [], { preferInstalled: false });
|
|
62
56
|
}
|
|
63
57
|
|
|
64
58
|
function buildPortableHookCommand(subcommand) {
|
|
65
|
-
return
|
|
59
|
+
return `${resolveCliBaseCommand()} ${subcommand}`;
|
|
66
60
|
}
|
|
67
61
|
|
|
68
62
|
function buildCodexPortableHookCommand(subcommand) {
|
|
69
|
-
return
|
|
63
|
+
return `${resolveCodexCliBaseCommand()} ${subcommand}`;
|
|
70
64
|
}
|
|
71
65
|
|
|
72
66
|
function preToolHookCommand() {
|
|
@@ -121,8 +115,8 @@ module.exports = {
|
|
|
121
115
|
packageVersion,
|
|
122
116
|
publishedHookCommandsAvailable,
|
|
123
117
|
preToolHookCommand,
|
|
124
|
-
|
|
125
|
-
|
|
118
|
+
resolveCodexCliBaseCommand,
|
|
119
|
+
resolveCliBaseCommand,
|
|
126
120
|
sessionStartHookCommand,
|
|
127
121
|
statuslineCommand,
|
|
128
122
|
userPromptHookCommand,
|
|
@@ -6,27 +6,11 @@
|
|
|
6
6
|
* Also used directly by the CLI to refresh statusline counters after feedback capture.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
const fs = require('
|
|
10
|
-
const
|
|
11
|
-
const path = require('node:path');
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
12
11
|
const { resolveFeedbackDir } = require('./feedback-paths');
|
|
13
|
-
const {
|
|
14
|
-
getAggregateStatuslineCachePath,
|
|
15
|
-
shouldAggregateFeedback,
|
|
16
|
-
} = require('./feedback-aggregate');
|
|
17
12
|
|
|
18
13
|
function getCachePath() {
|
|
19
|
-
const explicitFeedbackDir = process.env.THUMBGATE_FEEDBACK_DIR;
|
|
20
|
-
if (shouldAggregateFeedback() && explicitFeedbackDir) {
|
|
21
|
-
try {
|
|
22
|
-
if (path.resolve(explicitFeedbackDir).startsWith(path.resolve(os.tmpdir()) + path.sep)) {
|
|
23
|
-
return path.join(resolveFeedbackDir(), 'statusline_cache.json');
|
|
24
|
-
}
|
|
25
|
-
} catch {
|
|
26
|
-
return path.join(resolveFeedbackDir(), 'statusline_cache.json');
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
if (shouldAggregateFeedback()) return getAggregateStatuslineCachePath();
|
|
30
14
|
return path.join(resolveFeedbackDir(), 'statusline_cache.json');
|
|
31
15
|
}
|
|
32
16
|
|
|
@@ -18,11 +18,6 @@ const fs = require('fs');
|
|
|
18
18
|
const path = require('path');
|
|
19
19
|
const { resolveFeedbackDir } = require('./feedback-paths');
|
|
20
20
|
const { readJsonl } = require('./fs-utils');
|
|
21
|
-
const {
|
|
22
|
-
TRANSPORT_WORDS,
|
|
23
|
-
sanitizeFeedbackText,
|
|
24
|
-
transportWordsOnly,
|
|
25
|
-
} = require('./feedback-sanitizer');
|
|
26
21
|
|
|
27
22
|
// ---------------------------------------------------------------------------
|
|
28
23
|
// Paths
|
|
@@ -56,7 +51,6 @@ const STOPWORDS = new Set([
|
|
|
56
51
|
'has', 'had', 'not', 'but', 'they', 'you', 'can', 'will', 'all', 'any',
|
|
57
52
|
'one', 'its', 'our', 'also', 'more', 'very', 'just', 'into', 'been',
|
|
58
53
|
'bash', 'edit', 'write', 'tool', 'hook', 'clear',
|
|
59
|
-
...TRANSPORT_WORDS,
|
|
60
54
|
]);
|
|
61
55
|
|
|
62
56
|
const NEG = new Set([
|
|
@@ -80,7 +74,7 @@ const HYBRID_JSONL_READ_LIMIT = 400;
|
|
|
80
74
|
*/
|
|
81
75
|
function normalize(text) {
|
|
82
76
|
if (!text || typeof text !== 'string') return '';
|
|
83
|
-
return
|
|
77
|
+
return text
|
|
84
78
|
.replace(/\/Users\/[^\s/]+/g, '/Users/redacted')
|
|
85
79
|
.replace(/:\d{4,5}\b/g, ':PORT')
|
|
86
80
|
.toLowerCase()
|
|
@@ -103,9 +97,7 @@ function stripFeedbackPrefix(text) {
|
|
|
103
97
|
* Compose normalize + stripFeedbackPrefix.
|
|
104
98
|
*/
|
|
105
99
|
function normalizePatternText(text) {
|
|
106
|
-
|
|
107
|
-
if (transportWordsOnly(normalized)) return '';
|
|
108
|
-
return normalized;
|
|
100
|
+
return normalize(stripFeedbackPrefix(text));
|
|
109
101
|
}
|
|
110
102
|
|
|
111
103
|
/**
|
|
@@ -133,104 +125,6 @@ function classify(entry) {
|
|
|
133
125
|
return 'neutral';
|
|
134
126
|
}
|
|
135
127
|
|
|
136
|
-
function isHookPromptEnvelope(context) {
|
|
137
|
-
if (!context || typeof context !== 'string') return false;
|
|
138
|
-
try {
|
|
139
|
-
const parsed = JSON.parse(context);
|
|
140
|
-
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return false;
|
|
141
|
-
return Boolean(
|
|
142
|
-
parsed.prompt &&
|
|
143
|
-
(
|
|
144
|
-
parsed.hookEventName ||
|
|
145
|
-
parsed.hook_event_name ||
|
|
146
|
-
parsed.workspaceRoot ||
|
|
147
|
-
parsed.workspace_root ||
|
|
148
|
-
parsed.session_id ||
|
|
149
|
-
parsed.sessionId ||
|
|
150
|
-
parsed.transcript_path ||
|
|
151
|
-
parsed.transcriptPath
|
|
152
|
-
)
|
|
153
|
-
);
|
|
154
|
-
} catch (_) {
|
|
155
|
-
return false;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function patternContext(entry) {
|
|
160
|
-
const context = entry && entry.context ? String(entry.context) : '';
|
|
161
|
-
if (!context) return '';
|
|
162
|
-
const hasExplicitFeedback = Boolean(
|
|
163
|
-
entry.whatWentWrong ||
|
|
164
|
-
entry.what_went_wrong ||
|
|
165
|
-
entry.whatToChange ||
|
|
166
|
-
entry.what_to_change ||
|
|
167
|
-
entry.failureType ||
|
|
168
|
-
(Array.isArray(entry.tags) && entry.tags.length > 0) ||
|
|
169
|
-
entry.structuredRule
|
|
170
|
-
);
|
|
171
|
-
if (isHookPromptEnvelope(context) && !hasExplicitFeedback) return '';
|
|
172
|
-
if (isHookPromptEnvelope(context) && hasExplicitFeedback) {
|
|
173
|
-
return '';
|
|
174
|
-
}
|
|
175
|
-
return context;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Check if the feedback entry is an automated enforcement log (e.g. from gates engine)
|
|
180
|
-
* rather than real developer/user feedback.
|
|
181
|
-
*/
|
|
182
|
-
function isAutomatedFeedback(entry) {
|
|
183
|
-
const tags = entry.tags || [];
|
|
184
|
-
if (tags.includes('auto-capture') || tags.includes('gates-engine') || tags.includes('audit-trail')) {
|
|
185
|
-
return true;
|
|
186
|
-
}
|
|
187
|
-
const context = String(entry.context || entry.whatWentWrong || '').toLowerCase();
|
|
188
|
-
return context.includes('gate "') || context.includes('blocked tool') || context.includes('warned tool');
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
function isHookPromptEnvelope(context) {
|
|
193
|
-
if (!context || typeof context !== 'string') return false;
|
|
194
|
-
try {
|
|
195
|
-
const parsed = JSON.parse(context);
|
|
196
|
-
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return false;
|
|
197
|
-
return Boolean(
|
|
198
|
-
parsed.prompt &&
|
|
199
|
-
(
|
|
200
|
-
parsed.hookEventName ||
|
|
201
|
-
parsed.hook_event_name ||
|
|
202
|
-
parsed.workspaceRoot ||
|
|
203
|
-
parsed.workspace_root ||
|
|
204
|
-
parsed.session_id ||
|
|
205
|
-
parsed.sessionId ||
|
|
206
|
-
parsed.transcript_path ||
|
|
207
|
-
parsed.transcriptPath
|
|
208
|
-
)
|
|
209
|
-
);
|
|
210
|
-
} catch (_) {
|
|
211
|
-
return false;
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
function patternContext(entry) {
|
|
216
|
-
const context = entry && entry.context ? String(entry.context) : '';
|
|
217
|
-
if (!context) return '';
|
|
218
|
-
const hasExplicitFeedback = Boolean(
|
|
219
|
-
entry.whatWentWrong ||
|
|
220
|
-
entry.what_went_wrong ||
|
|
221
|
-
entry.whatToChange ||
|
|
222
|
-
entry.what_to_change ||
|
|
223
|
-
entry.failureType ||
|
|
224
|
-
(Array.isArray(entry.tags) && entry.tags.length > 0) ||
|
|
225
|
-
entry.structuredRule
|
|
226
|
-
);
|
|
227
|
-
if (isHookPromptEnvelope(context) && !hasExplicitFeedback) return '';
|
|
228
|
-
if (isHookPromptEnvelope(context) && hasExplicitFeedback) {
|
|
229
|
-
return '';
|
|
230
|
-
}
|
|
231
|
-
return context;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
128
|
/**
|
|
235
129
|
* Extract ms from a timestamp value. Returns 0 on failure.
|
|
236
130
|
*/
|
|
@@ -318,15 +212,13 @@ function buildHybridState(opts) {
|
|
|
318
212
|
if (cls === 'positive') positive++;
|
|
319
213
|
if (cls === 'negative') {
|
|
320
214
|
negative++;
|
|
321
|
-
// Track tool-level negative counts
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
toolNegatives[toolName] = (toolNegatives[toolName] || 0) + 1;
|
|
325
|
-
}
|
|
215
|
+
// Track tool-level negative counts
|
|
216
|
+
const toolName = inferToolName(entry.toolName || entry.tool_name || 'unknown', entry.context || '');
|
|
217
|
+
toolNegatives[toolName] = (toolNegatives[toolName] || 0) + 1;
|
|
326
218
|
|
|
327
219
|
// Build pattern from context / whatWentWrong / what_went_wrong
|
|
328
220
|
const rawText = [
|
|
329
|
-
|
|
221
|
+
entry.context || '',
|
|
330
222
|
entry.whatWentWrong || entry.what_went_wrong || '',
|
|
331
223
|
entry.whatToChange || entry.what_to_change || '',
|
|
332
224
|
entry.failureType || '',
|
|
@@ -362,13 +254,11 @@ function buildHybridState(opts) {
|
|
|
362
254
|
|
|
363
255
|
// Process attributed feedback separately to track attributed tool counts
|
|
364
256
|
for (const entry of attributedEntries) {
|
|
365
|
-
if (classify(entry) !== 'negative') continue; // skip pruned/positive
|
|
366
|
-
if (isAutomatedFeedback(entry)) continue; // skip automated gate blocks
|
|
367
257
|
const toolName = inferToolName(entry.toolName || entry.tool_name || entry.attributed_tool || 'unknown', entry.context || '');
|
|
368
258
|
toolNegativesAttributed[toolName] = (toolNegativesAttributed[toolName] || 0) + 1;
|
|
369
259
|
|
|
370
260
|
const rawText = [
|
|
371
|
-
|
|
261
|
+
entry.context || '',
|
|
372
262
|
entry.whatWentWrong || entry.what_went_wrong || '',
|
|
373
263
|
...(Array.isArray(entry.tags) ? entry.tags : []),
|
|
374
264
|
...(entry.richContext && Array.isArray(entry.richContext.filePaths) ? entry.richContext.filePaths : []),
|
|
@@ -730,36 +620,12 @@ function evaluatePretool(toolName, toolInput, opts) {
|
|
|
730
620
|
|
|
731
621
|
// Slow path: build live state (also used when compiled guards are stale)
|
|
732
622
|
const state = buildHybridState({
|
|
733
|
-
feedbackDir: o.feedbackDir,
|
|
734
623
|
feedbackLogPath: o.feedbackLogPath,
|
|
735
624
|
attributedFeedbackPath: o.attributedFeedbackPath,
|
|
736
625
|
});
|
|
737
626
|
return evaluatePretoolFromState(state, toolName, toolInput);
|
|
738
627
|
}
|
|
739
628
|
|
|
740
|
-
// Claw-style agent support (high-ROI for EnterpriseClaw / OpenShell agents from Automation Anywhere / Nvidia)
|
|
741
|
-
// Extends hybrid context for claw_action_type (file, screen, dynamic-tool, orchestration), agent_identity, hybrid_route.
|
|
742
|
-
// Use in evaluatePretool calls from claw-aware MCP/hooks: pass {clawContext: {actionType: 'dynamic-tool-creation', agentId: '...', route: 'local/cloud'}} in opts.
|
|
743
|
-
function evaluateClawPretool(toolName, toolInput, clawContext, opts) {
|
|
744
|
-
const o = opts || {};
|
|
745
|
-
const claw = clawContext || {};
|
|
746
|
-
// Merge claw metadata into toolInput for gate evaluation (so templates like block-dynamic-tool-creation can match)
|
|
747
|
-
const enrichedInput = {
|
|
748
|
-
...(typeof toolInput === 'object' ? toolInput : { raw: toolInput }),
|
|
749
|
-
_claw: {
|
|
750
|
-
actionType: claw.actionType || 'unknown',
|
|
751
|
-
agentId: claw.agentId || 'unknown',
|
|
752
|
-
hybridRoute: claw.hybridRoute || 'unknown',
|
|
753
|
-
screenInteraction: !!claw.screenInteraction,
|
|
754
|
-
fileAccess: !!claw.fileAccess,
|
|
755
|
-
}
|
|
756
|
-
};
|
|
757
|
-
const result = evaluatePretool(toolName, JSON.stringify(enrichedInput), o);
|
|
758
|
-
// Tag result with claw metadata for logging/feedback
|
|
759
|
-
result.clawContext = claw;
|
|
760
|
-
return result;
|
|
761
|
-
}
|
|
762
|
-
|
|
763
629
|
// ---------------------------------------------------------------------------
|
|
764
630
|
// CLI main()
|
|
765
631
|
// ---------------------------------------------------------------------------
|
|
@@ -808,7 +674,6 @@ function main() {
|
|
|
808
674
|
module.exports = {
|
|
809
675
|
buildHybridState,
|
|
810
676
|
evaluatePretool,
|
|
811
|
-
evaluateClawPretool,
|
|
812
677
|
compileGuardArtifact,
|
|
813
678
|
writeGuardArtifact,
|
|
814
679
|
readGuardArtifact,
|
|
@@ -18,7 +18,6 @@ const fs = require('fs');
|
|
|
18
18
|
const path = require('path');
|
|
19
19
|
const { resolveFeedbackDir } = require('./feedback-paths');
|
|
20
20
|
const { ensureParentDir, readJsonl } = require('./fs-utils');
|
|
21
|
-
const { redactSecretsDeep } = require('./secret-redaction');
|
|
22
21
|
const {
|
|
23
22
|
buildStableId,
|
|
24
23
|
extractFilePaths,
|
|
@@ -138,19 +137,15 @@ function createLesson({ feedbackId, signal, inferredLesson, triggerMessage, prio
|
|
|
138
137
|
// Stable link: dashboard deep-link to this lesson
|
|
139
138
|
lesson.link = `${getLessonBaseUrl()}/lessons#${lesson.id}`;
|
|
140
139
|
|
|
141
|
-
// Redact secrets before persisting — lesson text is derived from conversation content that may
|
|
142
|
-
// have captured a pasted credential. See scripts/secret-redaction.js.
|
|
143
|
-
const redactedLesson = redactSecretsDeep(lesson);
|
|
144
|
-
|
|
145
140
|
const lessonsPath = getLessonsPath();
|
|
146
141
|
ensureParentDir(lessonsPath);
|
|
147
|
-
fs.appendFileSync(lessonsPath, JSON.stringify(
|
|
142
|
+
fs.appendFileSync(lessonsPath, JSON.stringify(lesson) + '\n');
|
|
148
143
|
|
|
149
144
|
// Update recent lesson for statusbar
|
|
150
145
|
const recentPath = getRecentLessonPath();
|
|
151
|
-
fs.writeFileSync(recentPath, JSON.stringify(
|
|
146
|
+
fs.writeFileSync(recentPath, JSON.stringify(lesson, null, 2) + '\n');
|
|
152
147
|
|
|
153
|
-
return
|
|
148
|
+
return lesson;
|
|
154
149
|
}
|
|
155
150
|
|
|
156
151
|
/**
|
package/scripts/lesson-search.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const path = require('node:path');
|
|
4
4
|
const { readJSONL, getFeedbackPaths } = require('./feedback-loop');
|
|
5
|
-
const { buildMemoryLifecycleView, scoreHybridMemoryMatch } = require('./agent-memory-lifecycle');
|
|
6
5
|
const { loadOptionalModule } = require('./private-core-boundary');
|
|
7
6
|
|
|
8
7
|
const HIGH_RISK_TAGS = new Set([
|
|
@@ -412,8 +411,7 @@ function scoreLesson(queryText, memory, parsed, sourceFeedback) {
|
|
|
412
411
|
const score = jaccardSimilarity(queryTokens, lessonTokens)
|
|
413
412
|
+ substringBoost(queryText, lessonText)
|
|
414
413
|
+ recencyScore(memory.timestamp)
|
|
415
|
-
+ (memory.category === 'error' ? 0.05 : 0)
|
|
416
|
-
+ Math.min(0.2, scoreHybridMemoryMatch(queryText, memory).score * 0.1);
|
|
414
|
+
+ (memory.category === 'error' ? 0.05 : 0);
|
|
417
415
|
|
|
418
416
|
return {
|
|
419
417
|
score,
|
|
@@ -429,7 +427,6 @@ function buildLessonResult(memory, sourceFeedback, options = {}) {
|
|
|
429
427
|
const { score, matchedTokens } = scoreLesson(options.query || '', memory, parsed, sourceFeedback);
|
|
430
428
|
const harnessRecommendations = buildHarnessRecommendations(memory, parsed, sourceFeedback, ruleMatches, gateMatches);
|
|
431
429
|
const lifecycle = buildLifecycle(memory, parsed, sourceFeedback, ruleMatches, gateMatches, harnessRecommendations);
|
|
432
|
-
const memoryLifecycle = buildMemoryLifecycleView(memory, { query: options.query || '' });
|
|
433
430
|
|
|
434
431
|
return {
|
|
435
432
|
id: memory.id,
|
|
@@ -455,7 +452,6 @@ function buildLessonResult(memory, sourceFeedback, options = {}) {
|
|
|
455
452
|
systemResponse: {
|
|
456
453
|
promotedToMemory: true,
|
|
457
454
|
lifecycle,
|
|
458
|
-
memoryLifecycle,
|
|
459
455
|
diagnosis: memory.diagnosis || null,
|
|
460
456
|
sourceFeedback: sourceFeedback
|
|
461
457
|
? {
|
|
@@ -593,14 +589,6 @@ function tryFts5Search(query, options) {
|
|
|
593
589
|
tags: row.tags,
|
|
594
590
|
importance: row.importance,
|
|
595
591
|
timestamp: row.timestamp,
|
|
596
|
-
memoryLifecycle: buildMemoryLifecycleView({
|
|
597
|
-
title: row.context,
|
|
598
|
-
content: [row.whatWentWrong, row.whatToChange, row.whatWorked].filter(Boolean).join('\n'),
|
|
599
|
-
domain: row.domain,
|
|
600
|
-
tags: row.tags,
|
|
601
|
-
importance: row.importance,
|
|
602
|
-
timestamp: row.timestamp,
|
|
603
|
-
}, { query: query || '' }),
|
|
604
592
|
})),
|
|
605
593
|
backend: 'sqlite-fts5',
|
|
606
594
|
};
|
|
@@ -630,10 +618,6 @@ function formatLessonSearchResults(payload) {
|
|
|
630
618
|
payload.results.forEach((result, index) => {
|
|
631
619
|
lines.push(`${index + 1}. ${result.title}`);
|
|
632
620
|
lines.push(` Category: ${result.category} | Tags: ${result.tags.join(', ') || 'none'} | Score: ${result.score}`);
|
|
633
|
-
if (result.systemResponse.memoryLifecycle) {
|
|
634
|
-
const memoryLifecycle = result.systemResponse.memoryLifecycle;
|
|
635
|
-
lines.push(` Memory: scope=${memoryLifecycle.scope} | decay=${memoryLifecycle.decay.state} | hybrid=${memoryLifecycle.retrievalHints.hybridScore}`);
|
|
636
|
-
}
|
|
637
621
|
if (result.lesson.summary) {
|
|
638
622
|
lines.push(` Lesson: ${result.lesson.summary}`);
|
|
639
623
|
}
|