memhook 0.2.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/CHANGELOG.md +105 -0
- package/LICENSE +21 -0
- package/README.md +204 -0
- package/dist/bin/memhook.d.ts +16 -0
- package/dist/bin/memhook.d.ts.map +1 -0
- package/dist/bin/memhook.js +122 -0
- package/dist/bin/memhook.js.map +1 -0
- package/dist/src/cache.d.ts +30 -0
- package/dist/src/cache.d.ts.map +1 -0
- package/dist/src/cache.js +80 -0
- package/dist/src/cache.js.map +1 -0
- package/dist/src/catalog.d.ts +20 -0
- package/dist/src/catalog.d.ts.map +1 -0
- package/dist/src/catalog.js +152 -0
- package/dist/src/catalog.js.map +1 -0
- package/dist/src/config.d.ts +60 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +172 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/configFile.d.ts +54 -0
- package/dist/src/configFile.d.ts.map +1 -0
- package/dist/src/configFile.js +51 -0
- package/dist/src/configFile.js.map +1 -0
- package/dist/src/index.d.ts +20 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +19 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/preFilter.d.ts +16 -0
- package/dist/src/preFilter.d.ts.map +1 -0
- package/dist/src/preFilter.js +40 -0
- package/dist/src/preFilter.js.map +1 -0
- package/dist/src/providers/anthropic.d.ts +33 -0
- package/dist/src/providers/anthropic.d.ts.map +1 -0
- package/dist/src/providers/anthropic.js +98 -0
- package/dist/src/providers/anthropic.js.map +1 -0
- package/dist/src/providers/factory.d.ts +15 -0
- package/dist/src/providers/factory.d.ts.map +1 -0
- package/dist/src/providers/factory.js +37 -0
- package/dist/src/providers/factory.js.map +1 -0
- package/dist/src/providers/http.d.ts +34 -0
- package/dist/src/providers/http.d.ts.map +1 -0
- package/dist/src/providers/http.js +60 -0
- package/dist/src/providers/http.js.map +1 -0
- package/dist/src/providers/ollama.d.ts +30 -0
- package/dist/src/providers/ollama.d.ts.map +1 -0
- package/dist/src/providers/ollama.js +89 -0
- package/dist/src/providers/ollama.js.map +1 -0
- package/dist/src/providers/openai.d.ts +31 -0
- package/dist/src/providers/openai.d.ts.map +1 -0
- package/dist/src/providers/openai.js +94 -0
- package/dist/src/providers/openai.js.map +1 -0
- package/dist/src/providers/types.d.ts +48 -0
- package/dist/src/providers/types.d.ts.map +1 -0
- package/dist/src/providers/types.js +18 -0
- package/dist/src/providers/types.js.map +1 -0
- package/dist/src/router.d.ts +32 -0
- package/dist/src/router.d.ts.map +1 -0
- package/dist/src/router.js +342 -0
- package/dist/src/router.js.map +1 -0
- package/dist/src/version.d.ts +13 -0
- package/dist/src/version.d.ts.map +1 -0
- package/dist/src/version.js +13 -0
- package/dist/src/version.js.map +1 -0
- package/package.json +88 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memhook catalog builder — TS port of build-memory-catalog.sh.
|
|
3
|
+
*
|
|
4
|
+
* Discovers feedbacks & projects in `~/.claude/projects/* /memory/`, global
|
|
5
|
+
* rules in `~/.claude/rules/`, and project rules in `<cwd>/.claude/rules/`.
|
|
6
|
+
*
|
|
7
|
+
* Phase 0.5 Q4: title-only for non-CWD zones (~50% catalog size reduction).
|
|
8
|
+
* The CWD zone gets full `basename: description`; others list just basenames.
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, readFileSync, readdirSync, writeFileSync, statSync, renameSync, } from "node:fs";
|
|
11
|
+
import { join, basename as pathBasename } from "node:path";
|
|
12
|
+
import { homedir } from "node:os";
|
|
13
|
+
export function buildCatalog(opts) {
|
|
14
|
+
const home = homedir();
|
|
15
|
+
const projectsRoot = opts.projectsRoot ?? join(home, ".claude", "projects");
|
|
16
|
+
const globalRulesDir = opts.globalRulesDir ?? join(home, ".claude", "rules");
|
|
17
|
+
const memoryDirs = discoverMemoryDirs(projectsRoot, opts.cwd);
|
|
18
|
+
const sections = [];
|
|
19
|
+
sections.push(emitMemorySection("feedback", "MEMORY FEEDBACKS", memoryDirs));
|
|
20
|
+
sections.push(emitMemorySection("project", "MEMORY PROJECTS", memoryDirs));
|
|
21
|
+
sections.push(emitRulesSection("GLOBAL RULES", globalRulesDir, true));
|
|
22
|
+
sections.push(emitRulesSection(`PROJECT RULES (${pathBasename(opts.cwd)})`, join(opts.cwd, ".claude", "rules"), true));
|
|
23
|
+
const content = sections.join("\n");
|
|
24
|
+
const tmp = `${opts.outputPath}.tmp.${process.pid}`;
|
|
25
|
+
writeFileSync(tmp, content, "utf8");
|
|
26
|
+
renameSync(tmp, opts.outputPath);
|
|
27
|
+
const lines = content.split("\n").length;
|
|
28
|
+
const bytes = Buffer.byteLength(content, "utf8");
|
|
29
|
+
return { lines, bytes };
|
|
30
|
+
}
|
|
31
|
+
function discoverMemoryDirs(projectsRoot, cwd) {
|
|
32
|
+
if (!existsSync(projectsRoot))
|
|
33
|
+
return [];
|
|
34
|
+
const out = [];
|
|
35
|
+
const cwdSlug = cwdToSlug(cwd);
|
|
36
|
+
for (const entry of readdirSync(projectsRoot)) {
|
|
37
|
+
const dir = join(projectsRoot, entry, "memory");
|
|
38
|
+
if (!existsSync(dir))
|
|
39
|
+
continue;
|
|
40
|
+
out.push({ zoneSlug: entry, path: dir, isCwd: entry === cwdSlug });
|
|
41
|
+
}
|
|
42
|
+
// CWD first for Haiku priority
|
|
43
|
+
out.sort((a, b) => a.isCwd === b.isCwd ? a.zoneSlug.localeCompare(b.zoneSlug) : a.isCwd ? -1 : 1);
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
function cwdToSlug(cwd) {
|
|
47
|
+
// ~/.claude/projects encodes a POSIX path like `/Users/you/dev/app` as
|
|
48
|
+
// `-Users-you-dev-app`. On Windows, normalise backslashes first so a path
|
|
49
|
+
// like `C:\Users\you\dev\app` slugifies consistently (drive-letter matching
|
|
50
|
+
// is best-effort — Claude Code's Windows encoding is unverified).
|
|
51
|
+
return cwd.replace(/\\/g, "/").replace(/^\//, "-").replace(/\//g, "-");
|
|
52
|
+
}
|
|
53
|
+
function emitMemorySection(prefix, label, dirs) {
|
|
54
|
+
const lines = [`=== ${label} ===`];
|
|
55
|
+
let total = 0;
|
|
56
|
+
for (const dir of dirs) {
|
|
57
|
+
const files = listMemoryFiles(dir.path, prefix);
|
|
58
|
+
if (files.length === 0)
|
|
59
|
+
continue;
|
|
60
|
+
const marker = dir.isCwd ? " [CWD]" : "";
|
|
61
|
+
lines.push(`--- ${dir.zoneSlug}${marker} ---`);
|
|
62
|
+
for (const file of files) {
|
|
63
|
+
const bn = pathBasename(file);
|
|
64
|
+
if (dir.isCwd) {
|
|
65
|
+
lines.push(`${bn}: ${extractDescription(file)}`);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
lines.push(bn);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
total += files.length;
|
|
72
|
+
}
|
|
73
|
+
lines.push(`(${total} entries)`);
|
|
74
|
+
lines.push("");
|
|
75
|
+
return lines.join("\n");
|
|
76
|
+
}
|
|
77
|
+
function emitRulesSection(label, dir, isCwdZone) {
|
|
78
|
+
const lines = [`=== ${label} ===`];
|
|
79
|
+
if (!existsSync(dir)) {
|
|
80
|
+
lines.push(`(directory not found: ${dir})`);
|
|
81
|
+
lines.push("");
|
|
82
|
+
return lines.join("\n");
|
|
83
|
+
}
|
|
84
|
+
let count = 0;
|
|
85
|
+
for (const entry of readdirSync(dir).sort()) {
|
|
86
|
+
if (!entry.endsWith(".md"))
|
|
87
|
+
continue;
|
|
88
|
+
const full = join(dir, entry);
|
|
89
|
+
try {
|
|
90
|
+
const s = statSync(full);
|
|
91
|
+
if (!s.isFile())
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (isCwdZone) {
|
|
98
|
+
lines.push(`${entry}: ${extractDescription(full)}`);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
lines.push(entry);
|
|
102
|
+
}
|
|
103
|
+
count++;
|
|
104
|
+
}
|
|
105
|
+
lines.push(`(${count} entries)`);
|
|
106
|
+
lines.push("");
|
|
107
|
+
return lines.join("\n");
|
|
108
|
+
}
|
|
109
|
+
function listMemoryFiles(dir, prefix) {
|
|
110
|
+
let entries = [];
|
|
111
|
+
try {
|
|
112
|
+
entries = readdirSync(dir);
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
const re = new RegExp(`^${prefix}_.*\\.md$`);
|
|
118
|
+
return entries
|
|
119
|
+
.filter((e) => re.test(e))
|
|
120
|
+
.map((e) => join(dir, e))
|
|
121
|
+
.sort();
|
|
122
|
+
}
|
|
123
|
+
function extractDescription(file) {
|
|
124
|
+
let content = "";
|
|
125
|
+
try {
|
|
126
|
+
content = readFileSync(file, "utf8");
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return "";
|
|
130
|
+
}
|
|
131
|
+
// YAML frontmatter description
|
|
132
|
+
if (content.startsWith("---")) {
|
|
133
|
+
const end = content.indexOf("\n---", 3);
|
|
134
|
+
if (end > 0) {
|
|
135
|
+
const fm = content.slice(3, end);
|
|
136
|
+
const descMatch = fm.match(/^description:\s*(.+?)$/m);
|
|
137
|
+
if (descMatch?.[1]) {
|
|
138
|
+
return descMatch[1]
|
|
139
|
+
.trim()
|
|
140
|
+
.replace(/^["']|["']$/g, "")
|
|
141
|
+
.slice(0, 200)
|
|
142
|
+
.replace(/\s+/g, " ");
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// Fallback: first H1
|
|
147
|
+
const h1 = content.match(/^# (.+)$/m);
|
|
148
|
+
if (h1?.[1])
|
|
149
|
+
return h1[1].slice(0, 200).replace(/\s+/g, " ");
|
|
150
|
+
return "";
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/catalog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration resolution — env vars > config.yaml > defaults.
|
|
3
|
+
*
|
|
4
|
+
* Each key is resolved in exactly one place by a precedence-aware reader
|
|
5
|
+
* (`str`/`num`/`bool`): it reads the env var first, then the YAML file value
|
|
6
|
+
* (opt-in, loaded by `configFile.ts`), then a default. With no env vars and no
|
|
7
|
+
* `~/.config/memhook/config.yaml`, resolution collapses to the same defaults
|
|
8
|
+
* memhook shipped in v0.1, so existing Anthropic setups are unchanged.
|
|
9
|
+
*
|
|
10
|
+
* `loadConfig` is total — it must NEVER throw (it runs before the router's
|
|
11
|
+
* try-boundaries on some paths). All YAML I/O is isolated in `loadYamlConfig`,
|
|
12
|
+
* which swallows every error to null.
|
|
13
|
+
*/
|
|
14
|
+
export type ProviderType = "anthropic" | "openai" | "ollama";
|
|
15
|
+
export interface MemhookConfig {
|
|
16
|
+
enabled: boolean;
|
|
17
|
+
provider: {
|
|
18
|
+
type: ProviderType;
|
|
19
|
+
model: string;
|
|
20
|
+
/** Env var name holding the API key. `undefined` for keyless providers. */
|
|
21
|
+
apiKeyEnv: string | undefined;
|
|
22
|
+
baseUrl?: string | undefined;
|
|
23
|
+
/** Anthropic-only; forwarded to AnthropicProvider, ignored otherwise. */
|
|
24
|
+
betaHeaders: string[];
|
|
25
|
+
};
|
|
26
|
+
selection: {
|
|
27
|
+
maxFiles: number;
|
|
28
|
+
maxAdditionalChars: number;
|
|
29
|
+
maxOutputTokens: number;
|
|
30
|
+
curlTimeoutMs: number;
|
|
31
|
+
/** Anthropic-only ephemeral cache TTL; forwarded by the factory. */
|
|
32
|
+
cacheControlTtl: "5m" | "1h";
|
|
33
|
+
};
|
|
34
|
+
cache: {
|
|
35
|
+
enabled: boolean;
|
|
36
|
+
ttlMin: number;
|
|
37
|
+
dir: string;
|
|
38
|
+
evictionDays: number;
|
|
39
|
+
};
|
|
40
|
+
preFilter: {
|
|
41
|
+
enabled: boolean;
|
|
42
|
+
trivialWordsFile: string | undefined;
|
|
43
|
+
defaultWords: string[];
|
|
44
|
+
};
|
|
45
|
+
retry: {
|
|
46
|
+
enabled: boolean;
|
|
47
|
+
maxAttempts: number;
|
|
48
|
+
backoffMs: number;
|
|
49
|
+
};
|
|
50
|
+
catalog: {
|
|
51
|
+
path: string;
|
|
52
|
+
};
|
|
53
|
+
searchDirs: string[];
|
|
54
|
+
logging: {
|
|
55
|
+
jsonlPath: string;
|
|
56
|
+
};
|
|
57
|
+
scriptVersion: string;
|
|
58
|
+
}
|
|
59
|
+
export declare function loadConfig(env?: NodeJS.ProcessEnv): MemhookConfig;
|
|
60
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE7D,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE;QACR,IAAI,EAAE,YAAY,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,2EAA2E;QAC3E,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;QAC9B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC7B,yEAAyE;QACzE,WAAW,EAAE,MAAM,EAAE,CAAC;KACvB,CAAC;IACF,SAAS,EAAE;QACT,QAAQ,EAAE,MAAM,CAAC;QACjB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,eAAe,EAAE,MAAM,CAAC;QACxB,aAAa,EAAE,MAAM,CAAC;QACtB,oEAAoE;QACpE,eAAe,EAAE,IAAI,GAAG,IAAI,CAAC;KAC9B,CAAC;IACF,KAAK,EAAE;QACL,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,SAAS,EAAE;QACT,OAAO,EAAE,OAAO,CAAC;QACjB,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;QACrC,YAAY,EAAE,MAAM,EAAE,CAAC;KACxB,CAAC;IACF,KAAK,EAAE;QACL,OAAO,EAAE,OAAO,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE;QACP,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,aAAa,EAAE,MAAM,CAAC;CACvB;AAuDD,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,aAAa,CAyI9E"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration resolution — env vars > config.yaml > defaults.
|
|
3
|
+
*
|
|
4
|
+
* Each key is resolved in exactly one place by a precedence-aware reader
|
|
5
|
+
* (`str`/`num`/`bool`): it reads the env var first, then the YAML file value
|
|
6
|
+
* (opt-in, loaded by `configFile.ts`), then a default. With no env vars and no
|
|
7
|
+
* `~/.config/memhook/config.yaml`, resolution collapses to the same defaults
|
|
8
|
+
* memhook shipped in v0.1, so existing Anthropic setups are unchanged.
|
|
9
|
+
*
|
|
10
|
+
* `loadConfig` is total — it must NEVER throw (it runs before the router's
|
|
11
|
+
* try-boundaries on some paths). All YAML I/O is isolated in `loadYamlConfig`,
|
|
12
|
+
* which swallows every error to null.
|
|
13
|
+
*/
|
|
14
|
+
import { homedir } from "node:os";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
import { loadYamlConfig } from "./configFile.js";
|
|
17
|
+
import { MEMHOOK_VERSION } from "./version.js";
|
|
18
|
+
/** Per-provider defaults applied once the provider type is known. */
|
|
19
|
+
const PROVIDER_DEFAULTS = {
|
|
20
|
+
anthropic: { model: "claude-haiku-4-5", apiKeyEnv: "ANTHROPIC_API_KEY", timeoutMs: 8000 },
|
|
21
|
+
openai: { model: "gpt-4o-mini", apiKeyEnv: "OPENAI_API_KEY", timeoutMs: 8000 },
|
|
22
|
+
// Local models can be slow to cold-load into RAM/VRAM on the first call, so
|
|
23
|
+
// Ollama gets a more generous default timeout to avoid aborting every cold start.
|
|
24
|
+
ollama: { model: "llama3.1", apiKeyEnv: undefined, timeoutMs: 30000 },
|
|
25
|
+
};
|
|
26
|
+
const DEFAULT_TRIVIAL_WORDS = [
|
|
27
|
+
"ok",
|
|
28
|
+
"okay",
|
|
29
|
+
"oui",
|
|
30
|
+
"non",
|
|
31
|
+
"no",
|
|
32
|
+
"yes",
|
|
33
|
+
"yeah",
|
|
34
|
+
"yep",
|
|
35
|
+
"ouais",
|
|
36
|
+
"ouep",
|
|
37
|
+
"nope",
|
|
38
|
+
"merci",
|
|
39
|
+
"thanks",
|
|
40
|
+
"thx",
|
|
41
|
+
"stop",
|
|
42
|
+
"next",
|
|
43
|
+
"bien",
|
|
44
|
+
"nickel",
|
|
45
|
+
"parfait",
|
|
46
|
+
"hmm",
|
|
47
|
+
"hmmm",
|
|
48
|
+
"hmmmm",
|
|
49
|
+
"k",
|
|
50
|
+
"go",
|
|
51
|
+
"vasy",
|
|
52
|
+
"tupeux",
|
|
53
|
+
"lance",
|
|
54
|
+
"fais",
|
|
55
|
+
"continue",
|
|
56
|
+
"continu",
|
|
57
|
+
"allez",
|
|
58
|
+
"sure",
|
|
59
|
+
"sur",
|
|
60
|
+
"certain",
|
|
61
|
+
];
|
|
62
|
+
function isProviderType(v) {
|
|
63
|
+
return v === "anthropic" || v === "openai" || v === "ollama";
|
|
64
|
+
}
|
|
65
|
+
export function loadConfig(env = process.env) {
|
|
66
|
+
const home = homedir();
|
|
67
|
+
const yaml = loadYamlConfig(env);
|
|
68
|
+
// Precedence-aware readers: env > yaml > default. One call names each key once.
|
|
69
|
+
//
|
|
70
|
+
// Two robustness rules baked in here:
|
|
71
|
+
// 1. A present-but-empty/whitespace env var is treated as ABSENT (matches
|
|
72
|
+
// v0.1's `if (!v)` numeric handling), so `MEMHOOK_MAX_FILES=` falls
|
|
73
|
+
// through to yaml/default instead of coercing to 0/"".
|
|
74
|
+
// 2. The YAML value is parsed leniently and untrusted, so each reader
|
|
75
|
+
// type-narrows it at runtime — a wrong-typed key (string for a number,
|
|
76
|
+
// number for a bool) is ignored rather than leaking into typed config.
|
|
77
|
+
const envVal = (envKey) => {
|
|
78
|
+
const v = env[envKey];
|
|
79
|
+
return v !== undefined && v.trim() !== "" ? v : undefined;
|
|
80
|
+
};
|
|
81
|
+
const str = (envKey, yamlVal, def) => envVal(envKey) ?? (typeof yamlVal === "string" ? yamlVal : undefined) ?? def;
|
|
82
|
+
const strOpt = (envKey, yamlVal, def) => envVal(envKey) ?? (typeof yamlVal === "string" ? yamlVal : undefined) ?? def;
|
|
83
|
+
// Every numeric knob is a positive-integer count or duration, so a candidate
|
|
84
|
+
// is only accepted if it is a finite integer >= 1. This rejects degenerate
|
|
85
|
+
// values (negative caps, a 0ms timeout that aborts every request, NaN) by
|
|
86
|
+
// falling through to yaml/default instead of passing them on; fractions are
|
|
87
|
+
// floored. Defaults are trusted constants and pass through unchecked.
|
|
88
|
+
const posInt = (n) => Number.isFinite(n) && n >= 1 ? Math.floor(n) : undefined;
|
|
89
|
+
const num = (envKey, yamlVal, def) => {
|
|
90
|
+
const v = envVal(envKey);
|
|
91
|
+
if (v !== undefined) {
|
|
92
|
+
const fromEnv = posInt(Number(v));
|
|
93
|
+
if (fromEnv !== undefined)
|
|
94
|
+
return fromEnv;
|
|
95
|
+
}
|
|
96
|
+
const fromYaml = typeof yamlVal === "number" ? posInt(yamlVal) : undefined;
|
|
97
|
+
return fromYaml ?? def;
|
|
98
|
+
};
|
|
99
|
+
// Accepted truthy tokens, case-insensitive: true / 1 / yes / on.
|
|
100
|
+
const truthy = (v) => {
|
|
101
|
+
const t = v.trim().toLowerCase();
|
|
102
|
+
return t === "true" || t === "1" || t === "yes" || t === "on";
|
|
103
|
+
};
|
|
104
|
+
// Positive boolean (env wins, then yaml, then default).
|
|
105
|
+
const bool = (envKey, yamlVal, def) => {
|
|
106
|
+
const v = envVal(envKey);
|
|
107
|
+
if (v !== undefined)
|
|
108
|
+
return truthy(v);
|
|
109
|
+
return typeof yamlVal === "boolean" ? yamlVal : def;
|
|
110
|
+
};
|
|
111
|
+
// Inverted `MEMHOOK_DISABLE_*` env flag mapped onto a positive enabled value.
|
|
112
|
+
const enabledFromDisable = (disableEnvKey, yamlEnabled, def) => {
|
|
113
|
+
const v = envVal(disableEnvKey);
|
|
114
|
+
if (v !== undefined)
|
|
115
|
+
return !truthy(v);
|
|
116
|
+
return typeof yamlEnabled === "boolean" ? yamlEnabled : def;
|
|
117
|
+
};
|
|
118
|
+
// Provider type first; its per-provider defaults seed model/apiKeyEnv/timeout.
|
|
119
|
+
const rawType = envVal("MEMHOOK_PROVIDER") ?? yaml?.provider?.type;
|
|
120
|
+
const type = isProviderType(rawType) ? rawType : "anthropic";
|
|
121
|
+
const pdef = PROVIDER_DEFAULTS[type];
|
|
122
|
+
// betaHeaders is the one list-typed key; narrow to a string[] (Anthropic-only).
|
|
123
|
+
const yamlBetas = yaml?.provider?.betaHeaders;
|
|
124
|
+
const betaHeaders = Array.isArray(yamlBetas)
|
|
125
|
+
? yamlBetas.filter((h) => typeof h === "string")
|
|
126
|
+
: [];
|
|
127
|
+
return {
|
|
128
|
+
enabled: bool("MEMHOOK_ENABLED", yaml?.enabled, true),
|
|
129
|
+
provider: {
|
|
130
|
+
type,
|
|
131
|
+
model: str("MEMHOOK_MODEL", yaml?.provider?.model, pdef.model),
|
|
132
|
+
apiKeyEnv: strOpt("MEMHOOK_API_KEY_ENV", yaml?.provider?.apiKeyEnv, pdef.apiKeyEnv),
|
|
133
|
+
baseUrl: strOpt("MEMHOOK_BASE_URL", yaml?.provider?.baseUrl, undefined),
|
|
134
|
+
betaHeaders,
|
|
135
|
+
},
|
|
136
|
+
selection: {
|
|
137
|
+
maxFiles: num("MEMHOOK_MAX_FILES", yaml?.selection?.maxFiles, 5),
|
|
138
|
+
maxAdditionalChars: num("MEMHOOK_MAX_ADDITIONAL_CHARS", yaml?.selection?.maxAdditionalChars, 9500),
|
|
139
|
+
maxOutputTokens: num("MEMHOOK_MAX_OUTPUT_TOKENS", yaml?.selection?.maxOutputTokens, 200),
|
|
140
|
+
curlTimeoutMs: num("MEMHOOK_TIMEOUT_MS", yaml?.selection?.timeoutMs, pdef.timeoutMs),
|
|
141
|
+
cacheControlTtl: "1h",
|
|
142
|
+
},
|
|
143
|
+
cache: {
|
|
144
|
+
enabled: enabledFromDisable("MEMHOOK_DISABLE_CACHE", yaml?.cache?.enabled, true),
|
|
145
|
+
ttlMin: num("MEMHOOK_CACHE_TTL_MIN", yaml?.cache?.ttlMin, 60),
|
|
146
|
+
dir: str("MEMHOOK_CACHE_DIR", yaml?.cache?.dir, join(home, ".cache", "memhook")),
|
|
147
|
+
evictionDays: num("MEMHOOK_CACHE_EVICT_DAYS", yaml?.cache?.evictionDays, 7),
|
|
148
|
+
},
|
|
149
|
+
preFilter: {
|
|
150
|
+
enabled: enabledFromDisable("MEMHOOK_DISABLE_PREFILTER", yaml?.preFilter?.enabled, true),
|
|
151
|
+
trivialWordsFile: strOpt("MEMHOOK_TRIVIAL_FILE", yaml?.preFilter?.trivialWordsFile, join(home, ".config", "memhook", "trivial-words.txt")),
|
|
152
|
+
defaultWords: DEFAULT_TRIVIAL_WORDS,
|
|
153
|
+
},
|
|
154
|
+
retry: {
|
|
155
|
+
enabled: true,
|
|
156
|
+
maxAttempts: 2,
|
|
157
|
+
backoffMs: 500,
|
|
158
|
+
},
|
|
159
|
+
catalog: {
|
|
160
|
+
path: str("MEMHOOK_CATALOG_PATH", yaml?.catalog?.path, join(home, ".claude", "cache", "memory-catalog.txt")),
|
|
161
|
+
},
|
|
162
|
+
searchDirs: [
|
|
163
|
+
str("MEMHOOK_PROJECTS_ROOT", yaml?.searchDirs?.projectsRoot, join(home, ".claude", "projects")),
|
|
164
|
+
str("MEMHOOK_GLOBAL_RULES_DIR", yaml?.searchDirs?.globalRulesDir, join(home, ".claude", "rules")),
|
|
165
|
+
],
|
|
166
|
+
logging: {
|
|
167
|
+
jsonlPath: str("MEMHOOK_LOG_PATH", yaml?.logging?.jsonlPath, join(home, ".claude", "logs", "memhook.log")),
|
|
168
|
+
},
|
|
169
|
+
scriptVersion: MEMHOOK_VERSION,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional YAML config file loader.
|
|
3
|
+
*
|
|
4
|
+
* Resolution: `$MEMHOOK_CONFIG`, else `~/.config/memhook/config.yaml`. The file
|
|
5
|
+
* is entirely opt-in — when it is absent, `loadYamlConfig` returns null and the
|
|
6
|
+
* config layer collapses to exactly the env-var-or-default behaviour of v0.1.
|
|
7
|
+
*
|
|
8
|
+
* This module is the ONLY place YAML I/O happens, and it must NEVER throw: any
|
|
9
|
+
* error (missing file, unreadable, malformed YAML, non-object root) resolves to
|
|
10
|
+
* null so `loadConfig` stays total and the hook stays fail-soft. The `yaml`
|
|
11
|
+
* parser is lenient (it can return a partial object for malformed input), so
|
|
12
|
+
* callers must still treat the returned shape as untrusted and narrow each
|
|
13
|
+
* field — see `config.ts`.
|
|
14
|
+
*/
|
|
15
|
+
/** A YAML config mirrors a subset of MemhookConfig. Every key is optional. */
|
|
16
|
+
export interface RawConfigFile {
|
|
17
|
+
enabled?: boolean;
|
|
18
|
+
provider?: {
|
|
19
|
+
type?: string;
|
|
20
|
+
model?: string;
|
|
21
|
+
apiKeyEnv?: string;
|
|
22
|
+
baseUrl?: string;
|
|
23
|
+
betaHeaders?: string[];
|
|
24
|
+
};
|
|
25
|
+
selection?: {
|
|
26
|
+
maxFiles?: number;
|
|
27
|
+
maxAdditionalChars?: number;
|
|
28
|
+
maxOutputTokens?: number;
|
|
29
|
+
timeoutMs?: number;
|
|
30
|
+
};
|
|
31
|
+
cache?: {
|
|
32
|
+
enabled?: boolean;
|
|
33
|
+
ttlMin?: number;
|
|
34
|
+
dir?: string;
|
|
35
|
+
evictionDays?: number;
|
|
36
|
+
};
|
|
37
|
+
preFilter?: {
|
|
38
|
+
enabled?: boolean;
|
|
39
|
+
trivialWordsFile?: string;
|
|
40
|
+
};
|
|
41
|
+
catalog?: {
|
|
42
|
+
path?: string;
|
|
43
|
+
};
|
|
44
|
+
searchDirs?: {
|
|
45
|
+
projectsRoot?: string;
|
|
46
|
+
globalRulesDir?: string;
|
|
47
|
+
};
|
|
48
|
+
logging?: {
|
|
49
|
+
jsonlPath?: string;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export declare function resolveConfigPath(env: NodeJS.ProcessEnv): string;
|
|
53
|
+
export declare function loadYamlConfig(env: NodeJS.ProcessEnv): RawConfigFile | null;
|
|
54
|
+
//# sourceMappingURL=configFile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configFile.d.ts","sourceRoot":"","sources":["../../src/configFile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAOH,8EAA8E;AAC9E,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;KACxB,CAAC;IACF,SAAS,CAAC,EAAE;QACV,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,KAAK,CAAC,EAAE;QACN,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,SAAS,CAAC,EAAE;QACV,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;IACF,OAAO,CAAC,EAAE;QACR,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IACF,UAAU,CAAC,EAAE;QACX,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAEhE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,aAAa,GAAG,IAAI,CA2B3E"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional YAML config file loader.
|
|
3
|
+
*
|
|
4
|
+
* Resolution: `$MEMHOOK_CONFIG`, else `~/.config/memhook/config.yaml`. The file
|
|
5
|
+
* is entirely opt-in — when it is absent, `loadYamlConfig` returns null and the
|
|
6
|
+
* config layer collapses to exactly the env-var-or-default behaviour of v0.1.
|
|
7
|
+
*
|
|
8
|
+
* This module is the ONLY place YAML I/O happens, and it must NEVER throw: any
|
|
9
|
+
* error (missing file, unreadable, malformed YAML, non-object root) resolves to
|
|
10
|
+
* null so `loadConfig` stays total and the hook stays fail-soft. The `yaml`
|
|
11
|
+
* parser is lenient (it can return a partial object for malformed input), so
|
|
12
|
+
* callers must still treat the returned shape as untrusted and narrow each
|
|
13
|
+
* field — see `config.ts`.
|
|
14
|
+
*/
|
|
15
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
16
|
+
import { homedir } from "node:os";
|
|
17
|
+
import { join } from "node:path";
|
|
18
|
+
import { parse } from "yaml";
|
|
19
|
+
export function resolveConfigPath(env) {
|
|
20
|
+
return env["MEMHOOK_CONFIG"] ?? join(homedir(), ".config", "memhook", "config.yaml");
|
|
21
|
+
}
|
|
22
|
+
export function loadYamlConfig(env) {
|
|
23
|
+
const path = resolveConfigPath(env);
|
|
24
|
+
if (!existsSync(path))
|
|
25
|
+
return null;
|
|
26
|
+
let text;
|
|
27
|
+
try {
|
|
28
|
+
text = readFileSync(path, "utf8");
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
let parsed;
|
|
34
|
+
try {
|
|
35
|
+
// logLevel "error" keeps stray parser warnings off stderr (the hook must
|
|
36
|
+
// never emit noise). Malformed YAML throws YAMLParseError -> caught -> null.
|
|
37
|
+
parsed = parse(text, { logLevel: "error" });
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
if (env["MEMHOOK_DEBUG"] === "true") {
|
|
41
|
+
process.stderr.write(`memhook: ignoring unparseable config at ${path}\n`);
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
// The parser is lenient and may return scalars/arrays/null — only trust a
|
|
46
|
+
// plain object root.
|
|
47
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
48
|
+
return null;
|
|
49
|
+
return parsed;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=configFile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configFile.js","sourceRoot":"","sources":["../../src/configFile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAwC7B,MAAM,UAAU,iBAAiB,CAAC,GAAsB;IACtD,OAAO,GAAG,CAAC,gBAAgB,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC;AACvF,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAsB;IACnD,MAAM,IAAI,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAEnC,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,yEAAyE;QACzE,6EAA6E;QAC7E,MAAM,GAAG,KAAK,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,GAAG,CAAC,eAAe,CAAC,KAAK,MAAM,EAAE,CAAC;YACpC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,2CAA2C,IAAI,IAAI,CAAC,CAAC;QAC5E,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,0EAA0E;IAC1E,qBAAqB;IACrB,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAChF,OAAO,MAAuB,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memhook public API surface.
|
|
3
|
+
*
|
|
4
|
+
* Consumers typically don't import these directly — the package is invoked
|
|
5
|
+
* as a Claude Code hook via `memhook run` or `node dist/router.js`. Exposed
|
|
6
|
+
* here for programmatic embedding (tests, plugins, custom dashboards).
|
|
7
|
+
*/
|
|
8
|
+
export { loadConfig, type MemhookConfig, type ProviderType } from "./config.js";
|
|
9
|
+
export { loadYamlConfig, resolveConfigPath, type RawConfigFile } from "./configFile.js";
|
|
10
|
+
export { route, type HookInput, type HookOutput } from "./router.js";
|
|
11
|
+
export { buildCatalog, type CatalogBuildOptions } from "./catalog.js";
|
|
12
|
+
export { LocalCache, type CacheKeyInput } from "./cache.js";
|
|
13
|
+
export { PreFilter } from "./preFilter.js";
|
|
14
|
+
export { MEMHOOK_VERSION } from "./version.js";
|
|
15
|
+
export { createProvider } from "./providers/factory.js";
|
|
16
|
+
export { AnthropicProvider, type AnthropicProviderOptions } from "./providers/anthropic.js";
|
|
17
|
+
export { OpenAIProvider } from "./providers/openai.js";
|
|
18
|
+
export { OllamaProvider } from "./providers/ollama.js";
|
|
19
|
+
export type { Provider, ProviderConfig, SelectionRequest, SelectionResponse, UsageBreakdown, } from "./providers/types.js";
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAChF,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACxF,OAAO,EAAE,KAAK,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,KAAK,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAC5F,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,YAAY,EACV,QAAQ,EACR,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,GACf,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memhook public API surface.
|
|
3
|
+
*
|
|
4
|
+
* Consumers typically don't import these directly — the package is invoked
|
|
5
|
+
* as a Claude Code hook via `memhook run` or `node dist/router.js`. Exposed
|
|
6
|
+
* here for programmatic embedding (tests, plugins, custom dashboards).
|
|
7
|
+
*/
|
|
8
|
+
export { loadConfig } from "./config.js";
|
|
9
|
+
export { loadYamlConfig, resolveConfigPath } from "./configFile.js";
|
|
10
|
+
export { route } from "./router.js";
|
|
11
|
+
export { buildCatalog } from "./catalog.js";
|
|
12
|
+
export { LocalCache } from "./cache.js";
|
|
13
|
+
export { PreFilter } from "./preFilter.js";
|
|
14
|
+
export { MEMHOOK_VERSION } from "./version.js";
|
|
15
|
+
export { createProvider } from "./providers/factory.js";
|
|
16
|
+
export { AnthropicProvider } from "./providers/anthropic.js";
|
|
17
|
+
export { OpenAIProvider } from "./providers/openai.js";
|
|
18
|
+
export { OllamaProvider } from "./providers/ollama.js";
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAyC,MAAM,aAAa,CAAC;AAChF,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAsB,MAAM,iBAAiB,CAAC;AACxF,OAAO,EAAE,KAAK,EAAmC,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,YAAY,EAA4B,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,UAAU,EAAsB,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAiC,MAAM,0BAA0B,CAAC;AAC5F,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-filter trivial prompts — skip the LLM call entirely on acks like
|
|
3
|
+
* "ok", "yeah", "merci", etc. Conservative by design: better to false-negative
|
|
4
|
+
* (call Haiku unnecessarily) than false-positive (skip a real prompt).
|
|
5
|
+
*
|
|
6
|
+
* Strategy:
|
|
7
|
+
* - Strip whitespace and punctuation from the prompt
|
|
8
|
+
* - Lowercase
|
|
9
|
+
* - Exact match against the trivial word list (file > defaults)
|
|
10
|
+
*/
|
|
11
|
+
export declare class PreFilter {
|
|
12
|
+
private readonly words;
|
|
13
|
+
constructor(filePath: string | undefined, defaults: string[]);
|
|
14
|
+
isTrivial(prompt: string): boolean;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=preFilter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preFilter.d.ts","sourceRoot":"","sources":["../../src/preFilter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAc;gBAExB,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE;IAgB5D,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;CAKnC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-filter trivial prompts — skip the LLM call entirely on acks like
|
|
3
|
+
* "ok", "yeah", "merci", etc. Conservative by design: better to false-negative
|
|
4
|
+
* (call Haiku unnecessarily) than false-positive (skip a real prompt).
|
|
5
|
+
*
|
|
6
|
+
* Strategy:
|
|
7
|
+
* - Strip whitespace and punctuation from the prompt
|
|
8
|
+
* - Lowercase
|
|
9
|
+
* - Exact match against the trivial word list (file > defaults)
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
12
|
+
export class PreFilter {
|
|
13
|
+
words;
|
|
14
|
+
constructor(filePath, defaults) {
|
|
15
|
+
let words = defaults;
|
|
16
|
+
if (filePath && existsSync(filePath)) {
|
|
17
|
+
try {
|
|
18
|
+
const raw = readFileSync(filePath, "utf8");
|
|
19
|
+
words = raw
|
|
20
|
+
.split(/\r?\n/)
|
|
21
|
+
.map((line) => line.trim())
|
|
22
|
+
.filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// fall back to defaults silently
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
this.words = new Set(words.map((w) => normalise(w)));
|
|
29
|
+
}
|
|
30
|
+
isTrivial(prompt) {
|
|
31
|
+
const trim = normalise(prompt);
|
|
32
|
+
if (trim.length === 0)
|
|
33
|
+
return true;
|
|
34
|
+
return this.words.has(trim);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function normalise(input) {
|
|
38
|
+
return input.replace(/[\s\p{P}]/gu, "").toLowerCase();
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=preFilter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preFilter.js","sourceRoot":"","sources":["../../src/preFilter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEnD,MAAM,OAAO,SAAS;IACH,KAAK,CAAc;IAEpC,YAAY,QAA4B,EAAE,QAAkB;QAC1D,IAAI,KAAK,GAAG,QAAQ,CAAC;QACrB,IAAI,QAAQ,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACrC,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;gBAC3C,KAAK,GAAG,GAAG;qBACR,KAAK,CAAC,OAAO,CAAC;qBACd,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;qBAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;YAChE,CAAC;YAAC,MAAM,CAAC;gBACP,iCAAiC;YACnC,CAAC;QACH,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACvD,CAAC;IAED,SAAS,CAAC,MAAc;QACtB,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACnC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;CACF;AAED,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,KAAK,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;AACxD,CAAC"}
|