opencode-harnmem 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +45 -2
- package/index.js +512 -0
- package/lib/engine.mjs +72 -0
- package/lib/format.mjs +119 -0
- package/lib/settings.mjs +131 -0
- package/package.json +23 -3
- package/vendor/core/assets.d.ts +52 -0
- package/vendor/core/assets.d.ts.map +1 -0
- package/vendor/core/assets.js +227 -0
- package/vendor/core/assets.js.map +1 -0
- package/vendor/core/config.d.ts +36 -0
- package/vendor/core/config.d.ts.map +1 -0
- package/vendor/core/config.js +134 -0
- package/vendor/core/config.js.map +1 -0
- package/vendor/core/consolidate.d.ts +14 -0
- package/vendor/core/consolidate.d.ts.map +1 -0
- package/vendor/core/consolidate.js +237 -0
- package/vendor/core/consolidate.js.map +1 -0
- package/vendor/core/data/synonyms.en.txt +61 -0
- package/vendor/core/data/synonyms.zh.txt +157 -0
- package/vendor/core/extract.d.ts +49 -0
- package/vendor/core/extract.d.ts.map +1 -0
- package/vendor/core/extract.js +179 -0
- package/vendor/core/extract.js.map +1 -0
- package/vendor/core/frontmatter.d.ts +31 -0
- package/vendor/core/frontmatter.d.ts.map +1 -0
- package/vendor/core/frontmatter.js +372 -0
- package/vendor/core/frontmatter.js.map +1 -0
- package/vendor/core/harnmem.d.ts +87 -0
- package/vendor/core/harnmem.d.ts.map +1 -0
- package/vendor/core/harnmem.js +918 -0
- package/vendor/core/harnmem.js.map +1 -0
- package/vendor/core/hot-context.d.ts +28 -0
- package/vendor/core/hot-context.d.ts.map +1 -0
- package/vendor/core/hot-context.js +179 -0
- package/vendor/core/hot-context.js.map +1 -0
- package/vendor/core/index.d.ts +16 -0
- package/vendor/core/index.d.ts.map +1 -0
- package/vendor/core/index.js +10 -0
- package/vendor/core/index.js.map +1 -0
- package/vendor/core/indexer.d.ts +107 -0
- package/vendor/core/indexer.d.ts.map +1 -0
- package/vendor/core/indexer.js +282 -0
- package/vendor/core/indexer.js.map +1 -0
- package/vendor/core/inspect.d.ts +278 -0
- package/vendor/core/inspect.d.ts.map +1 -0
- package/vendor/core/inspect.js +643 -0
- package/vendor/core/inspect.js.map +1 -0
- package/vendor/core/lifecycle.d.ts +50 -0
- package/vendor/core/lifecycle.d.ts.map +1 -0
- package/vendor/core/lifecycle.js +249 -0
- package/vendor/core/lifecycle.js.map +1 -0
- package/vendor/core/project.d.ts +41 -0
- package/vendor/core/project.d.ts.map +1 -0
- package/vendor/core/project.js +197 -0
- package/vendor/core/project.js.map +1 -0
- package/vendor/core/prompts/README.md +96 -0
- package/vendor/core/prompts/consolidate-digest.md +31 -0
- package/vendor/core/prompts/extract.md +80 -0
- package/vendor/core/prompts/migrate.md +96 -0
- package/vendor/core/prompts/synonyms.md +43 -0
- package/vendor/core/prompts/write-policy.md +12 -0
- package/vendor/core/retrieval.d.ts +95 -0
- package/vendor/core/retrieval.d.ts.map +1 -0
- package/vendor/core/retrieval.js +569 -0
- package/vendor/core/retrieval.js.map +1 -0
- package/vendor/core/store.d.ts +145 -0
- package/vendor/core/store.d.ts.map +1 -0
- package/vendor/core/store.js +511 -0
- package/vendor/core/store.js.map +1 -0
- package/vendor/core/suggest.d.ts +128 -0
- package/vendor/core/suggest.d.ts.map +1 -0
- package/vendor/core/suggest.js +384 -0
- package/vendor/core/suggest.js.map +1 -0
- package/vendor/core/text.d.ts +80 -0
- package/vendor/core/text.d.ts.map +1 -0
- package/vendor/core/text.js +253 -0
- package/vendor/core/text.js.map +1 -0
- package/vendor/core/types.d.ts +453 -0
- package/vendor/core/types.d.ts.map +1 -0
- package/vendor/core/types.js +14 -0
- package/vendor/core/types.js.map +1 -0
- package/vendor/core/util.d.ts +38 -0
- package/vendor/core/util.d.ts.map +1 -0
- package/vendor/core/util.js +248 -0
- package/vendor/core/util.js.map +1 -0
package/lib/format.mjs
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model-facing text formatting for MCP tool results and /memory output.
|
|
3
|
+
* Port of packages/pi-harnmem/src/format.ts so every harness shows identical
|
|
4
|
+
* tool-output shapes. Tool results are the only place where live data may
|
|
5
|
+
* appear; the injected snapshot stays byte-stable (nothing here is injected).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const MAX_TOOL_TEXT = 12_000;
|
|
9
|
+
|
|
10
|
+
function clip(text, max = MAX_TOOL_TEXT) {
|
|
11
|
+
if (text.length <= max) return text;
|
|
12
|
+
return text.slice(0, max) + `\n…[truncated ${text.length - max} chars]`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function fmtTime(ms) {
|
|
16
|
+
if (!ms) return "-";
|
|
17
|
+
return new Date(ms).toISOString().slice(0, 10);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function formatWrite(result) {
|
|
21
|
+
const lines = [];
|
|
22
|
+
switch (result.action) {
|
|
23
|
+
case "NEW":
|
|
24
|
+
lines.push(`stored ${result.id} (NEW)`);
|
|
25
|
+
break;
|
|
26
|
+
case "SKIP":
|
|
27
|
+
lines.push(`already exists ${result.id} (SKIP)`);
|
|
28
|
+
break;
|
|
29
|
+
case "MERGE":
|
|
30
|
+
lines.push(`merged into ${result.id} (MERGE)`);
|
|
31
|
+
break;
|
|
32
|
+
case "SUPERSEDE":
|
|
33
|
+
lines.push(`superseded ${result.superseded.join(", ") || "(none)"} → ${result.id}`);
|
|
34
|
+
break;
|
|
35
|
+
case "LINK":
|
|
36
|
+
lines.push(`linked to existing ${result.id} (LINK)`);
|
|
37
|
+
break;
|
|
38
|
+
default:
|
|
39
|
+
lines.push(`write result: ${result.action} ${result.id}`);
|
|
40
|
+
}
|
|
41
|
+
if (result.warnings?.length) lines.push(`warnings: ${result.warnings.join("; ")}`);
|
|
42
|
+
// Contract (docs/adapter-authoring.md §2): the write tool returns exactly one
|
|
43
|
+
// line — "stored mem_x (NEW)" / "(SKIP)" / "superseded a → b" — no guidance.
|
|
44
|
+
return clip(lines.join("\n"));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function formatSearch(result) {
|
|
48
|
+
if (result.abstained || result.results.length === 0) {
|
|
49
|
+
return clip(
|
|
50
|
+
`no confident memories for "${result.query}" (abstained). Try different keywords, or the memory status tool to inspect the store.`,
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
const lines = [`${result.results.length}/${result.total} matches for "${result.query}":`];
|
|
54
|
+
for (const hit of result.results) {
|
|
55
|
+
const flags = [hit.status !== "active" ? hit.status : "", hit.pinned ? "pinned" : "", hit.historical ? "historical" : ""]
|
|
56
|
+
.filter(Boolean)
|
|
57
|
+
.join(",");
|
|
58
|
+
lines.push(
|
|
59
|
+
`- ${hit.id} [${hit.type}${hit.category ? "/" + hit.category : ""}${flags ? " (" + flags + ")" : ""}] ${hit.title} — ${hit.description}` +
|
|
60
|
+
(hit.snippet ? `\n ${hit.snippet.replace(/\s+/g, " ").slice(0, 240)}` : ""),
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
if (result.debug) {
|
|
64
|
+
// Defensive (matches the codex adapter): shards is typed string[] but a
|
|
65
|
+
// hostile/host-reshaped object must not throw inside a tool result.
|
|
66
|
+
const shards = Array.isArray(result.debug.shards) ? result.debug.shards.join(",") : String(result.debug.shards ?? "?");
|
|
67
|
+
lines.push(`debug: candidates=${result.debug.candidateCount} shards=${shards} elapsed=${result.debug.elapsedMs}ms`);
|
|
68
|
+
}
|
|
69
|
+
lines.push("Call the memory read tool with a hit id to open the record.");
|
|
70
|
+
return clip(lines.join("\n"));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function formatRead(result, id) {
|
|
74
|
+
if (!result) return `not found: ${id}`;
|
|
75
|
+
const r = result.record;
|
|
76
|
+
const lines = [
|
|
77
|
+
`${r.id} [${r.type}${r.category ? "/" + r.category : ""}] ${r.scope}${r.project ? "/" + r.project : ""} status=${r.status} importance=${r.importance} confidence=${r.confidence}${r.pinned ? " pinned" : ""}`,
|
|
78
|
+
`title: ${r.title}`,
|
|
79
|
+
`description: ${r.description}`,
|
|
80
|
+
`updated: ${fmtTime(r.updated)} created: ${fmtTime(r.created)} valid: ${fmtTime(r.validFrom)} → ${r.validTo ? fmtTime(r.validTo) : "now"}`,
|
|
81
|
+
];
|
|
82
|
+
if (r.tags?.length) lines.push(`tags: ${r.tags.join(", ")}`);
|
|
83
|
+
if (r.entities?.length) lines.push(`entities: ${r.entities.join(", ")}`);
|
|
84
|
+
if (r.links?.length) lines.push(`links: ${r.links.join(", ")}`);
|
|
85
|
+
if (result.backlinks?.length) lines.push(`backlinks: ${result.backlinks.join(", ")}`);
|
|
86
|
+
if (result.history?.length) lines.push(`history: ${result.history.map((h) => h.id).join(", ")}`);
|
|
87
|
+
lines.push("", r.content);
|
|
88
|
+
return clip(lines.join("\n"));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function formatForget(result) {
|
|
92
|
+
return result.ok
|
|
93
|
+
? result.mode === "hard"
|
|
94
|
+
? `permanently deleted ${result.id}`
|
|
95
|
+
: `moved ${result.id} to trash (restorable for the grace period; restore with the harnmem CLI)`
|
|
96
|
+
: `could not forget ${result.id}`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function formatStats(stats) {
|
|
100
|
+
const lines = [
|
|
101
|
+
`harnmem v${stats.version} home=${stats.home}`,
|
|
102
|
+
`project: ${stats.project ?? "(none)"}`,
|
|
103
|
+
`index: seq=${stats.index.seq} stale=${stats.index.stale} built=${fmtTime(stats.index.builtAt)} size=${stats.index.sizeBytes}B overhead=${(stats.index.overhead * 100).toFixed(0)}%`,
|
|
104
|
+
];
|
|
105
|
+
for (const shard of stats.shards) {
|
|
106
|
+
lines.push(
|
|
107
|
+
`shard ${shard.name} [${shard.scope}] total=${shard.total} active=${shard.active} superseded=${shard.superseded} archived=${shard.archived} pinned=${shard.pinned} ${Math.round(shard.bytes / 1024)}KB`,
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
if (stats.shards.length === 0) lines.push("no shards yet (empty store)");
|
|
111
|
+
lines.push(
|
|
112
|
+
`health: overBudget=${stats.health.overBudget} duplicates=${stats.health.duplicateCandidates} orphans=${stats.health.orphans} lastConsolidate=${stats.health.lastConsolidate ? fmtTime(stats.health.lastConsolidate) : "never"}`,
|
|
113
|
+
);
|
|
114
|
+
lines.push(
|
|
115
|
+
`extraction: pending=${stats.extraction.pending} failed=${stats.extraction.failed}` +
|
|
116
|
+
(Object.keys(stats.extraction.skipReasons).length ? ` skip=${JSON.stringify(stats.extraction.skipReasons)}` : ""),
|
|
117
|
+
);
|
|
118
|
+
return clip(lines.join("\n"));
|
|
119
|
+
}
|
package/lib/settings.mjs
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settings resolution for the opencode adapter.
|
|
3
|
+
*
|
|
4
|
+
* Priority (low -> high), matching docs/design/07-adapter-contract.md §7:
|
|
5
|
+
* 1. `<home>/config.json` (default `~/.harnmem/config.json`)
|
|
6
|
+
* 2. `<cwd>/.harnmem.json` (project config)
|
|
7
|
+
* 3. environment variables (HARNMEM_HOME, HARNMEM_DISABLED, ...)
|
|
8
|
+
*
|
|
9
|
+
* The chain and defaults are identical to the claude adapter; only the
|
|
10
|
+
* max-inject-tokens env var is harness-scoped. Malformed JSON is ignored,
|
|
11
|
+
* never fatal.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
15
|
+
import { homedir } from "node:os";
|
|
16
|
+
import path from "node:path";
|
|
17
|
+
|
|
18
|
+
const KNOWN_KEYS = ["enabled", "readOnly", "inject", "autoExtract", "debug", "home", "project", "maxInjectTokens"];
|
|
19
|
+
|
|
20
|
+
const DEFAULTS = {
|
|
21
|
+
enabled: true,
|
|
22
|
+
readOnly: false,
|
|
23
|
+
inject: true,
|
|
24
|
+
autoExtract: false,
|
|
25
|
+
debug: false,
|
|
26
|
+
maxInjectTokens: 1200,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function truthy(value) {
|
|
30
|
+
if (value === undefined) return undefined;
|
|
31
|
+
const v = String(value).trim().toLowerCase();
|
|
32
|
+
if (v === "" || v === "0" || v === "false" || v === "no" || v === "off") return false;
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Expand a leading `~` to the user home before path.resolve(): core would
|
|
38
|
+
* expand it, but by then the adapter has already resolved `~/x` into
|
|
39
|
+
* `<cwd>\~\x`. Probed failure mode shared with the other adapters.
|
|
40
|
+
*/
|
|
41
|
+
function expandHome(value) {
|
|
42
|
+
if (typeof value !== "string") return value;
|
|
43
|
+
const t = value.trim();
|
|
44
|
+
if (t === "~") return homedir();
|
|
45
|
+
if (t.startsWith("~/") || t.startsWith("~\\")) return path.join(homedir(), t.slice(2));
|
|
46
|
+
return t;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function readSettingsFile(file) {
|
|
50
|
+
if (!existsSync(file)) return undefined;
|
|
51
|
+
try {
|
|
52
|
+
const parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
53
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return undefined;
|
|
54
|
+
return parsed;
|
|
55
|
+
} catch {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function pickKnown(source) {
|
|
61
|
+
if (!source) return {};
|
|
62
|
+
const out = {};
|
|
63
|
+
// Skip null explicitly: "enabled": null in a config file must fall back to
|
|
64
|
+
// the default (true), not be treated as a falsy override that disables the
|
|
65
|
+
// store.
|
|
66
|
+
for (const key of KNOWN_KEYS) {
|
|
67
|
+
if (source[key] === undefined || source[key] === null) continue;
|
|
68
|
+
out[key] = source[key];
|
|
69
|
+
}
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const BOOL_KEYS = ["enabled", "readOnly", "inject", "autoExtract", "debug"];
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Config files are user-edited JSON: coerce boolean-ish strings the same way
|
|
77
|
+
* the env path does ("enabled": "false" must disable, not stay truthy), and
|
|
78
|
+
* validate maxInjectTokens like the env path (no strings/zero/negatives
|
|
79
|
+
* straight into core's token budget).
|
|
80
|
+
*/
|
|
81
|
+
function coerceFileValues(settings) {
|
|
82
|
+
for (const key of BOOL_KEYS) {
|
|
83
|
+
if (typeof settings[key] !== "string") continue;
|
|
84
|
+
const v = truthy(settings[key]);
|
|
85
|
+
if (v === undefined) delete settings[key];
|
|
86
|
+
else settings[key] = v;
|
|
87
|
+
}
|
|
88
|
+
if (settings.maxInjectTokens !== undefined) {
|
|
89
|
+
const n = Number(settings.maxInjectTokens);
|
|
90
|
+
if (!Number.isFinite(n) || n <= 0) delete settings.maxInjectTokens;
|
|
91
|
+
else settings.maxInjectTokens = Math.floor(n);
|
|
92
|
+
}
|
|
93
|
+
return settings;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function resolveSettings(cwd = process.cwd(), env = process.env) {
|
|
97
|
+
const envHome = expandHome(env.HARNMEM_HOME);
|
|
98
|
+
const baseHome = envHome && envHome.trim() ? path.resolve(envHome) : path.join(homedir(), ".harnmem");
|
|
99
|
+
|
|
100
|
+
let settings = { ...DEFAULTS };
|
|
101
|
+
settings = coerceFileValues({ ...settings, ...pickKnown(readSettingsFile(path.join(baseHome, "config.json"))) });
|
|
102
|
+
settings = coerceFileValues({ ...settings, ...pickKnown(readSettingsFile(path.join(cwd, ".harnmem.json"))) });
|
|
103
|
+
|
|
104
|
+
const disabled = truthy(env.HARNMEM_DISABLED);
|
|
105
|
+
if (disabled !== undefined) settings.enabled = !disabled;
|
|
106
|
+
const ro = truthy(env.HARNMEM_READONLY);
|
|
107
|
+
if (ro !== undefined) settings.readOnly = ro;
|
|
108
|
+
const dbg = truthy(env.HARNMEM_DEBUG);
|
|
109
|
+
if (dbg !== undefined) settings.debug = dbg;
|
|
110
|
+
const ae = truthy(env.HARNMEM_AUTO_EXTRACT);
|
|
111
|
+
if (ae !== undefined) settings.autoExtract = ae;
|
|
112
|
+
const inj = truthy(env.HARNMEM_INJECT);
|
|
113
|
+
if (inj !== undefined) settings.inject = inj;
|
|
114
|
+
if (env.HARNMEM_OPENCODE_MAX_INJECT_TOKENS) {
|
|
115
|
+
const n = Number(env.HARNMEM_OPENCODE_MAX_INJECT_TOKENS);
|
|
116
|
+
if (Number.isFinite(n) && n > 0) settings.maxInjectTokens = Math.floor(n);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const home =
|
|
120
|
+
envHome && envHome.trim()
|
|
121
|
+
? path.resolve(envHome)
|
|
122
|
+
: typeof settings.home === "string" && settings.home.trim()
|
|
123
|
+
? path.resolve(expandHome(settings.home))
|
|
124
|
+
: baseHome;
|
|
125
|
+
|
|
126
|
+
return { ...settings, home };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function debugEnabled(settings) {
|
|
130
|
+
return settings.debug === true;
|
|
131
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-harnmem",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "opencode v2 plugin for HarnMem: byte-stable memory injection (session context hook), five native memory tools, and per-turn session journaling — in-process, zero runtime dependencies.",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"files": [
|
|
9
|
+
"index.js",
|
|
10
|
+
"lib/",
|
|
11
|
+
"vendor/",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"main": "index.js",
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@harnmem/core": "0.4.0"
|
|
18
|
+
},
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=22.15"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "node scripts/vendor.mjs",
|
|
24
|
+
"test": "node --test test/*.test.mjs"
|
|
25
|
+
}
|
|
6
26
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export interface PromptAsset {
|
|
2
|
+
name: string;
|
|
3
|
+
version: number;
|
|
4
|
+
/** Stable system prompt (no placeholders). */
|
|
5
|
+
system: string;
|
|
6
|
+
/** User template with {{placeholders}}; null for legacy single-string prompts. */
|
|
7
|
+
user: string | null;
|
|
8
|
+
/** Where the asset was read from (diagnostics). */
|
|
9
|
+
source: string;
|
|
10
|
+
}
|
|
11
|
+
/** Repository/package root that contains `prompts/extract.md`, if discoverable. */
|
|
12
|
+
export declare function findAssetRoot(): string | null;
|
|
13
|
+
/** Read an asset, preferring the user's copy in <home>, then the shipped default. */
|
|
14
|
+
export declare function readAssetRaw(home: string, relativePath: string): {
|
|
15
|
+
text: string;
|
|
16
|
+
source: string;
|
|
17
|
+
} | null;
|
|
18
|
+
/**
|
|
19
|
+
* Synonym tables available to the engine: shipped defaults plus the user's
|
|
20
|
+
* editable copies, deduplicated by filename and sorted for deterministic
|
|
21
|
+
* loading. A language is added by adding `data/synonyms.<lang>.txt` — no code
|
|
22
|
+
* change; the `<home>` copy of a filename overrides the shipped default of the
|
|
23
|
+
* same name.
|
|
24
|
+
*/
|
|
25
|
+
export declare function listSynonymFiles(home: string): string[];
|
|
26
|
+
/**
|
|
27
|
+
* Parse one synonym table. Shipped format is `canonical<TAB>syn1,syn2`;
|
|
28
|
+
* `=`, `:` and full-width `:` are accepted as separators too, and synonyms may
|
|
29
|
+
* be separated by `,`, `,` or `、`. Blank lines and `#` comments are ignored.
|
|
30
|
+
*/
|
|
31
|
+
export declare function parseSynonymTable(raw: string): string[][];
|
|
32
|
+
/** All synonym groups from every discovered table; `files` is for diagnostics. */
|
|
33
|
+
export declare function loadSynonymGroups(home: string): {
|
|
34
|
+
groups: string[][];
|
|
35
|
+
files: string[];
|
|
36
|
+
};
|
|
37
|
+
/** Split a prompt file into stable system text + user template. */
|
|
38
|
+
export declare function parsePromptAsset(name: string, raw: string, source?: string): PromptAsset;
|
|
39
|
+
/** Load a prompt asset from <home>/prompts or the shipped defaults. */
|
|
40
|
+
export declare function loadPromptAsset(home: string, name: string): PromptAsset | null;
|
|
41
|
+
/** Replace `{{name}}` placeholders. Unknown placeholders are left in place on purpose. */
|
|
42
|
+
export declare function fillPrompt(template: string, vars: Record<string, string>): string;
|
|
43
|
+
export interface DeployResult {
|
|
44
|
+
copied: string[];
|
|
45
|
+
root: string | null;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Copy shipped defaults into <home>/ the first time they are needed. Existing
|
|
49
|
+
* user files are never overwritten. Returns copied paths (home-relative).
|
|
50
|
+
*/
|
|
51
|
+
export declare function deployDefaultAssets(home: string): DeployResult;
|
|
52
|
+
//# sourceMappingURL=assets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../src/assets.ts"],"names":[],"mappings":"AAoBA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,kFAAkF;IAClF,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;CAChB;AAID,mFAAmF;AACnF,wBAAgB,aAAa,IAAI,MAAM,GAAG,IAAI,CAwB7C;AAED,qFAAqF;AACrF,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAaxG;AAQD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAevD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,CAazD;AAED,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAQvF;AAED,mEAAmE;AACnE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,SAAa,GAAG,WAAW,CAqC5F;AAED,uEAAuE;AACvE,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAI9E;AAED,0FAA0F;AAC1F,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAMjF;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CA0B9D"}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt/data asset loading + first-run deployment.
|
|
3
|
+
*
|
|
4
|
+
* Assets are plain files so users can edit them:
|
|
5
|
+
* <home>/prompts/*.md extraction / consolidation prompts
|
|
6
|
+
* <home>/data/*.txt tokenizer synonym tables
|
|
7
|
+
*
|
|
8
|
+
* Shipped defaults live at the repository (or package) root next to `packages/`,
|
|
9
|
+
* found by walking up from this module. When that root is unavailable (e.g. a
|
|
10
|
+
* bundled single-file build) callers fall back to the constants in extract.ts.
|
|
11
|
+
*
|
|
12
|
+
* Prompt file contract (see prompts/README.md): HTML comments are metadata and
|
|
13
|
+
* stripped at load time; a prompt file may contain `## system` and `## user`
|
|
14
|
+
* sections. Placeholders `{{name}}` are only allowed in the user section so the
|
|
15
|
+
* system prompt stays byte-stable for KV-cache reuse.
|
|
16
|
+
*/
|
|
17
|
+
import { copyFileSync, existsSync, mkdirSync, readdirSync, readFileSync } from "node:fs";
|
|
18
|
+
import { dirname, join, resolve } from "node:path";
|
|
19
|
+
import { fileURLToPath } from "node:url";
|
|
20
|
+
let assetRootCache;
|
|
21
|
+
/** Repository/package root that contains `prompts/extract.md`, if discoverable. */
|
|
22
|
+
export function findAssetRoot() {
|
|
23
|
+
if (assetRootCache !== undefined)
|
|
24
|
+
return assetRootCache;
|
|
25
|
+
const candidates = [];
|
|
26
|
+
const env = process.env.HARNMEM_ASSETS_DIR;
|
|
27
|
+
if (env)
|
|
28
|
+
candidates.push(resolve(env));
|
|
29
|
+
try {
|
|
30
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
31
|
+
for (let i = 0; i < 8; i += 1) {
|
|
32
|
+
candidates.push(dir);
|
|
33
|
+
const parent = dirname(dir);
|
|
34
|
+
if (parent === dir)
|
|
35
|
+
break;
|
|
36
|
+
dir = parent;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// import.meta.url is always available in ESM; ignore exotic loaders.
|
|
41
|
+
}
|
|
42
|
+
for (const candidate of candidates) {
|
|
43
|
+
if (existsSync(join(candidate, "prompts", "extract.md"))) {
|
|
44
|
+
assetRootCache = candidate;
|
|
45
|
+
return candidate;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
assetRootCache = null;
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
/** Read an asset, preferring the user's copy in <home>, then the shipped default. */
|
|
52
|
+
export function readAssetRaw(home, relativePath) {
|
|
53
|
+
const candidates = [join(home, relativePath)];
|
|
54
|
+
const root = findAssetRoot();
|
|
55
|
+
if (root)
|
|
56
|
+
candidates.push(join(root, relativePath));
|
|
57
|
+
for (const file of candidates) {
|
|
58
|
+
try {
|
|
59
|
+
const text = readFileSync(file, "utf8");
|
|
60
|
+
if (text.trim())
|
|
61
|
+
return { text, source: file };
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// try next candidate
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Language-tagged synonym tables: `synonyms.zh.txt`, `synonyms.en.txt`, ...;
|
|
71
|
+
* a bare `synonyms.txt` is accepted too.
|
|
72
|
+
*/
|
|
73
|
+
const SYNONYM_FILE_RE = /^synonyms(?:\.[a-z0-9_-]+)?\.txt$/i;
|
|
74
|
+
/**
|
|
75
|
+
* Synonym tables available to the engine: shipped defaults plus the user's
|
|
76
|
+
* editable copies, deduplicated by filename and sorted for deterministic
|
|
77
|
+
* loading. A language is added by adding `data/synonyms.<lang>.txt` — no code
|
|
78
|
+
* change; the `<home>` copy of a filename overrides the shipped default of the
|
|
79
|
+
* same name.
|
|
80
|
+
*/
|
|
81
|
+
export function listSynonymFiles(home) {
|
|
82
|
+
const names = new Set();
|
|
83
|
+
const collect = (root) => {
|
|
84
|
+
if (!root)
|
|
85
|
+
return;
|
|
86
|
+
try {
|
|
87
|
+
for (const file of readdirSync(join(root, "data"))) {
|
|
88
|
+
if (SYNONYM_FILE_RE.test(file))
|
|
89
|
+
names.add(file);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// optional directory
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
collect(home);
|
|
97
|
+
collect(findAssetRoot());
|
|
98
|
+
return [...names].sort();
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Parse one synonym table. Shipped format is `canonical<TAB>syn1,syn2`;
|
|
102
|
+
* `=`, `:` and full-width `:` are accepted as separators too, and synonyms may
|
|
103
|
+
* be separated by `,`, `,` or `、`. Blank lines and `#` comments are ignored.
|
|
104
|
+
*/
|
|
105
|
+
export function parseSynonymTable(raw) {
|
|
106
|
+
const groups = [];
|
|
107
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
108
|
+
const trimmed = line.trim();
|
|
109
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
110
|
+
continue;
|
|
111
|
+
const match = /^([^\t=::]+)[\t=::]+(.+)$/.exec(trimmed);
|
|
112
|
+
if (!match)
|
|
113
|
+
continue;
|
|
114
|
+
const head = match[1];
|
|
115
|
+
const tail = match[2];
|
|
116
|
+
const group = [head, ...tail.split(/[,,、]/)].map((s) => s.trim()).filter(Boolean);
|
|
117
|
+
if (group.length >= 2)
|
|
118
|
+
groups.push(group);
|
|
119
|
+
}
|
|
120
|
+
return groups;
|
|
121
|
+
}
|
|
122
|
+
/** All synonym groups from every discovered table; `files` is for diagnostics. */
|
|
123
|
+
export function loadSynonymGroups(home) {
|
|
124
|
+
const files = listSynonymFiles(home);
|
|
125
|
+
const groups = [];
|
|
126
|
+
for (const file of files) {
|
|
127
|
+
const asset = readAssetRaw(home, join("data", file));
|
|
128
|
+
if (asset)
|
|
129
|
+
groups.push(...parseSynonymTable(asset.text));
|
|
130
|
+
}
|
|
131
|
+
return { groups, files };
|
|
132
|
+
}
|
|
133
|
+
/** Split a prompt file into stable system text + user template. */
|
|
134
|
+
export function parsePromptAsset(name, raw, source = "(inline)") {
|
|
135
|
+
const header = /<!--\s*version:\s*(\d+)\s*-->/i.exec(raw);
|
|
136
|
+
const version = header ? Number(header[1]) : 1;
|
|
137
|
+
const stripped = raw.replace(/<!--[\s\S]*?-->/g, "").replace(/\r\n/g, "\n");
|
|
138
|
+
const lines = stripped.split("\n");
|
|
139
|
+
const sections = {
|
|
140
|
+
system: [],
|
|
141
|
+
user: [],
|
|
142
|
+
current: "system",
|
|
143
|
+
};
|
|
144
|
+
const markers = [];
|
|
145
|
+
lines.forEach((line, index) => {
|
|
146
|
+
const match = /^\s*##\s+(system|user)\s*$/.exec(line);
|
|
147
|
+
if (match) {
|
|
148
|
+
markers.push({ at: index, kind: match[1] });
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
let system;
|
|
152
|
+
let user = null;
|
|
153
|
+
if (markers.length === 0) {
|
|
154
|
+
// Legacy custom prompt: whole file is the system prompt.
|
|
155
|
+
system = stripped.trim();
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
const first = markers[0];
|
|
159
|
+
const body = lines.slice(0, first.at).join("\n").trim();
|
|
160
|
+
if (body)
|
|
161
|
+
sections.system.push(body);
|
|
162
|
+
for (let i = 0; i < markers.length; i += 1) {
|
|
163
|
+
const marker = markers[i];
|
|
164
|
+
const next = markers[i + 1];
|
|
165
|
+
const chunk = lines.slice(marker.at + 1, next ? next.at : lines.length).join("\n").trim();
|
|
166
|
+
if (marker.kind === "system")
|
|
167
|
+
sections.system.push(chunk);
|
|
168
|
+
else
|
|
169
|
+
sections.user.push(chunk);
|
|
170
|
+
}
|
|
171
|
+
system = sections.system.filter(Boolean).join("\n\n").trim();
|
|
172
|
+
user = sections.user.filter(Boolean).join("\n\n").trim() || null;
|
|
173
|
+
}
|
|
174
|
+
return { name, version, system, user, source };
|
|
175
|
+
}
|
|
176
|
+
/** Load a prompt asset from <home>/prompts or the shipped defaults. */
|
|
177
|
+
export function loadPromptAsset(home, name) {
|
|
178
|
+
const found = readAssetRaw(home, join("prompts", `${name}.md`));
|
|
179
|
+
if (!found)
|
|
180
|
+
return null;
|
|
181
|
+
return parsePromptAsset(name, found.text, found.source);
|
|
182
|
+
}
|
|
183
|
+
/** Replace `{{name}}` placeholders. Unknown placeholders are left in place on purpose. */
|
|
184
|
+
export function fillPrompt(template, vars) {
|
|
185
|
+
let out = template;
|
|
186
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
187
|
+
out = out.split(`{{${key}}}`).join(value);
|
|
188
|
+
}
|
|
189
|
+
return out;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Copy shipped defaults into <home>/ the first time they are needed. Existing
|
|
193
|
+
* user files are never overwritten. Returns copied paths (home-relative).
|
|
194
|
+
*/
|
|
195
|
+
export function deployDefaultAssets(home) {
|
|
196
|
+
const root = findAssetRoot();
|
|
197
|
+
if (!root)
|
|
198
|
+
return { copied: [], root: null };
|
|
199
|
+
const copied = [];
|
|
200
|
+
const copyTree = (relDir, filter) => {
|
|
201
|
+
const fromDir = join(root, relDir);
|
|
202
|
+
if (!existsSync(fromDir))
|
|
203
|
+
return;
|
|
204
|
+
const toDir = join(home, relDir);
|
|
205
|
+
mkdirSync(toDir, { recursive: true });
|
|
206
|
+
for (const file of readdirSync(fromDir)) {
|
|
207
|
+
if (!filter(file))
|
|
208
|
+
continue;
|
|
209
|
+
const from = join(fromDir, file);
|
|
210
|
+
const to = join(toDir, file);
|
|
211
|
+
if (existsSync(to))
|
|
212
|
+
continue;
|
|
213
|
+
try {
|
|
214
|
+
readFileSync(from); // existence/readability check
|
|
215
|
+
copyFileSync(from, to);
|
|
216
|
+
copied.push(join(relDir, file).replace(/\\/g, "/"));
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
// deployment is best-effort
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
copyTree("prompts", (file) => file.endsWith(".md") || file.endsWith(".txt"));
|
|
224
|
+
copyTree("data", (file) => file.endsWith(".txt") || file.endsWith(".tsv"));
|
|
225
|
+
return { copied, root };
|
|
226
|
+
}
|
|
227
|
+
//# sourceMappingURL=assets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assets.js","sourceRoot":"","sources":["../src/assets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACzF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAazC,IAAI,cAAyC,CAAC;AAE9C,mFAAmF;AACnF,MAAM,UAAU,aAAa;IAC3B,IAAI,cAAc,KAAK,SAAS;QAAE,OAAO,cAAc,CAAC;IACxD,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAC3C,IAAI,GAAG;QAAE,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IACvC,IAAI,CAAC;QACH,IAAI,GAAG,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAClD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACrB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;YAC5B,IAAI,MAAM,KAAK,GAAG;gBAAE,MAAM;YAC1B,GAAG,GAAG,MAAM,CAAC;QACf,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,qEAAqE;IACvE,CAAC;IACD,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC;YACzD,cAAc,GAAG,SAAS,CAAC;YAC3B,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IACD,cAAc,GAAG,IAAI,CAAC;IACtB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,YAAoB;IAC7D,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,aAAa,EAAE,CAAC;IAC7B,IAAI,IAAI;QAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC;IACpD,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACxC,IAAI,IAAI,CAAC,IAAI,EAAE;gBAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QACjD,CAAC;QAAC,MAAM,CAAC;YACP,qBAAqB;QACvB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,eAAe,GAAG,oCAAoC,CAAC;AAE7D;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,MAAM,OAAO,GAAG,CAAC,IAAmB,EAAQ,EAAE;QAC5C,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,IAAI,CAAC;YACH,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;gBACnD,IAAI,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;oBAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAClD,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,qBAAqB;QACvB,CAAC;IACH,CAAC,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC;IACd,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;IACzB,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;AAC3B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,MAAM,MAAM,GAAe,EAAE,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACtC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAClD,MAAM,KAAK,GAAG,2BAA2B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxD,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAW,CAAC;QAChC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAW,CAAC;QAChC,MAAM,KAAK,GAAG,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAClF,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,MAAM,GAAe,EAAE,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;QACrD,IAAI,KAAK;YAAE,MAAM,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAC3B,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,GAAW,EAAE,MAAM,GAAG,UAAU;IAC7E,MAAM,MAAM,GAAG,gCAAgC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1D,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC5E,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,QAAQ,GAAqE;QACjF,MAAM,EAAE,EAAE;QACV,IAAI,EAAE,EAAE;QACR,OAAO,EAAE,QAAQ;KAClB,CAAC;IACF,MAAM,OAAO,GAAmD,EAAE,CAAC;IACnE,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC5B,MAAM,KAAK,GAAG,4BAA4B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtD,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAsB,EAAE,CAAC,CAAC;QACnE,CAAC;IACH,CAAC,CAAC,CAAC;IACH,IAAI,MAAc,CAAC;IACnB,IAAI,IAAI,GAAkB,IAAI,CAAC;IAC/B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,yDAAyD;QACzD,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC3B,CAAC;SAAM,CAAC;QACN,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAA4C,CAAC;QACpE,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QACxD,IAAI,IAAI;YAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3C,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAA4C,CAAC;YACrE,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAwD,CAAC;YACnF,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YAC1F,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ;gBAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;;gBACrD,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC;QACD,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7D,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC;IACnE,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AACjD,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,IAAY;IACxD,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC;IAChE,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,OAAO,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;AAC1D,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,UAAU,CAAC,QAAgB,EAAE,IAA4B;IACvE,IAAI,GAAG,GAAG,QAAQ,CAAC;IACnB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAOD;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,MAAM,IAAI,GAAG,aAAa,EAAE,CAAC;IAC7B,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC7C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAG,CAAC,MAAc,EAAE,MAAiC,EAAQ,EAAE;QAC3E,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACnC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;YAAE,OAAO;QACjC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACjC,SAAS,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;YACxC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;gBAAE,SAAS;YAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YACjC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YAC7B,IAAI,UAAU,CAAC,EAAE,CAAC;gBAAE,SAAS;YAC7B,IAAI,CAAC;gBACH,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,8BAA8B;gBAClD,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBACvB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;YACtD,CAAC;YAAC,MAAM,CAAC;gBACP,4BAA4B;YAC9B,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IACF,QAAQ,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IAC7E,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IAC3E,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { BudgetConfig, HarnMemConfig, GovernanceConfig, RetrievalConfig, WriteConfig } from "./types.js";
|
|
2
|
+
import { type FieldConfig } from "./text.js";
|
|
3
|
+
export declare const DEFAULT_BUDGET: BudgetConfig;
|
|
4
|
+
type FullRetrieval = RetrievalConfig;
|
|
5
|
+
type FullWrite = WriteConfig;
|
|
6
|
+
type FullGovernance = GovernanceConfig;
|
|
7
|
+
export declare const DEFAULT_RETRIEVAL: FullRetrieval;
|
|
8
|
+
export declare const DEFAULT_WRITE: FullWrite;
|
|
9
|
+
export declare const DEFAULT_GOVERNANCE: FullGovernance;
|
|
10
|
+
export interface Defaults {
|
|
11
|
+
home: string;
|
|
12
|
+
harness: string;
|
|
13
|
+
cwd: string;
|
|
14
|
+
now: () => number;
|
|
15
|
+
budget: BudgetConfig;
|
|
16
|
+
retrieval: FullRetrieval;
|
|
17
|
+
write: FullWrite;
|
|
18
|
+
governance: FullGovernance;
|
|
19
|
+
}
|
|
20
|
+
export declare const DEFAULT_CONFIG: Defaults;
|
|
21
|
+
export declare function mergeConfig(base: HarnMemConfig, override: HarnMemConfig | undefined): HarnMemConfig;
|
|
22
|
+
/**
|
|
23
|
+
* Load config from the home config file and the project-local `.harnmem.json`
|
|
24
|
+
* (if any), then apply explicit overrides.
|
|
25
|
+
*/
|
|
26
|
+
export declare function loadConfig(home: string, projectRoot: string | undefined, explicit: HarnMemConfig | undefined): Promise<HarnMemConfig>;
|
|
27
|
+
export declare function fieldsOf(config: HarnMemConfig): FieldConfig;
|
|
28
|
+
/** Resolved ttl days for a type. */
|
|
29
|
+
export declare function ttlDays(config: HarnMemConfig, type: string): number;
|
|
30
|
+
/** Resolved retrieval config with all defaults applied. */
|
|
31
|
+
export declare function retrievalOf(config: HarnMemConfig): FullRetrieval;
|
|
32
|
+
export declare function writeOf(config: HarnMemConfig): FullWrite;
|
|
33
|
+
export declare function governanceOf(config: HarnMemConfig): FullGovernance;
|
|
34
|
+
export declare function budgetOf(config: HarnMemConfig): BudgetConfig;
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,WAAW,EACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAG7D,eAAO,MAAM,cAAc,EAAE,YAK5B,CAAC;AAEF,KAAK,aAAa,GAAG,eAAe,CAAC;AACrC,KAAK,SAAS,GAAG,WAAW,CAAC;AAC7B,KAAK,cAAc,GAAG,gBAAgB,CAAC;AAEvC,eAAO,MAAM,iBAAiB,EAAE,aAe/B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,SAQ3B,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,cAQhC,CAAC;AAEF,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,EAAE,aAAa,CAAC;IACzB,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,EAAE,cAAc,CAAC;CAC5B;AAED,eAAO,MAAM,cAAc,EAAE,QAS5B,CAAC;AAEF,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,aAAa,GAAG,SAAS,GAAG,aAAa,CAcnG;AAYD;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,QAAQ,EAAE,aAAa,GAAG,SAAS,GAClC,OAAO,CAAC,aAAa,CAAC,CAWxB;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,aAAa,GAAG,WAAW,CAE3D;AAED,oCAAoC;AACpC,wBAAgB,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAInE;AAED,2DAA2D;AAC3D,wBAAgB,WAAW,CAAC,MAAM,EAAE,aAAa,GAAG,aAAa,CAEhE;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG,SAAS,CAExD;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,cAAc,CAElE;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,aAAa,GAAG,YAAY,CAE5D"}
|