@metaharness/kernel 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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 RuvNet (https://ruv.io)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # @metaharness/kernel
2
+
3
+ Cross-platform kernel for the [agent-harness-generator](https://github.com/ruvnet/agent-harness-generator) project.
4
+
5
+ ## What it is
6
+
7
+ A Rust kernel compiled to two npm-shippable targets:
8
+
9
+ - **WebAssembly** (primary distribution — runs on Node, browser, Cloudflare Workers, Deno, Bun, edge)
10
+ - **NAPI-RS native** (per-platform `.node` binaries — escape hatch for Node hot paths)
11
+
12
+ At load time, `loadKernel()` prefers the per-platform native package; falls back to wasm.
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ npm install @metaharness/kernel
18
+ ```
19
+
20
+ The native packages (`@metaharness/kernel-darwin-arm64`, `-linux-x64-gnu`, etc.) are declared as `optionalDependencies` — npm installs only the one for your platform.
21
+
22
+ ## Usage
23
+
24
+ ```js
25
+ import { loadKernel } from '@metaharness/kernel';
26
+
27
+ const kernel = await loadKernel();
28
+ const info = kernel.kernelInfo();
29
+ console.log(`kernel ${info.version} (${kernel.backend})`);
30
+
31
+ // Validate an MCP server spec.
32
+ const err = kernel.mcpValidate(JSON.stringify({
33
+ name: 'demo',
34
+ command: ['npx', '-y', 'demo'],
35
+ }));
36
+ if (err) throw new Error(err);
37
+ ```
38
+
39
+ ### Memory subsystem (subpath export)
40
+
41
+ ```js
42
+ import { rankWithDecay } from '@metaharness/kernel/memory';
43
+
44
+ const ranked = await rankWithDecay(hits, {
45
+ useDecay: true,
46
+ halfLifeMs: 7 * 24 * 60 * 60 * 1000, // 7-day half-life
47
+ });
48
+ ```
49
+
50
+ Wraps `@ruvector/emergent-time` for HNSW decay scoring.
51
+
52
+ ## Subsystems
53
+
54
+ | Subsystem | What it does |
55
+ |---|---|
56
+ | `mcp` | MCP server spec + tool registry |
57
+ | `hooks` | Lifecycle hook dispatch with permission-decision merge |
58
+ | `memory` | AgentDB bridge + emergent-time decay weighting |
59
+ | `routing` | 3-tier routing (codemod / Haiku / Sonnet-Opus) |
60
+ | `intel` | Intelligence pipeline phases |
61
+ | `claims` | Claims-based authorization |
62
+ | `witness` | Ed25519-signed provenance manifests |
63
+
64
+ ## License
65
+
66
+ MIT
@@ -0,0 +1,45 @@
1
+ export interface ToolHandler {
2
+ (args: Record<string, unknown>): Promise<unknown>;
3
+ }
4
+ export interface ToolClaim {
5
+ capability: string;
6
+ resource?: string;
7
+ expires_at: number;
8
+ }
9
+ export interface DispatchOptions {
10
+ server: string;
11
+ tool: string;
12
+ args: Record<string, unknown>;
13
+ claims: ToolClaim[];
14
+ resource?: string;
15
+ }
16
+ export type DispatchOutcome = {
17
+ kind: 'result';
18
+ output: unknown;
19
+ } | {
20
+ kind: 'denied';
21
+ reason: string;
22
+ } | {
23
+ kind: 'not-found';
24
+ server: string;
25
+ tool: string;
26
+ } | {
27
+ kind: 'bad-args';
28
+ reason: string;
29
+ };
30
+ /**
31
+ * In-process tool dispatcher. Use for harnesses that register tool
32
+ * handlers directly in TS (host adapter wraps these).
33
+ */
34
+ export declare class ToolDispatcher {
35
+ private handlers;
36
+ private key;
37
+ register(server: string, tool: string, handler: ToolHandler): void;
38
+ has(server: string, tool: string): boolean;
39
+ /**
40
+ * Execute the dispatch. Returns the structured outcome rather than
41
+ * throwing so callers can branch on the result type.
42
+ */
43
+ dispatch(opts: DispatchOptions, nowUnix?: number): Promise<DispatchOutcome>;
44
+ }
45
+ //# sourceMappingURL=dispatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,WAAW;IAC1B,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACnD;AAED,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzC;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAkC;IAElD,OAAO,CAAC,GAAG;IAIX,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI;IAIlE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1C;;;OAGG;IACG,QAAQ,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,GAAE,MAAsC,GAAG,OAAO,CAAC,eAAe,CAAC;CAwBjH"}
@@ -0,0 +1,74 @@
1
+ // SPDX-License-Identifier: MIT
2
+ //
3
+ // TS-side MCP tool dispatch wrapper.
4
+ //
5
+ // The Rust kernel owns the dispatch decision (look up tool, shape-check
6
+ // args, claims check). This TS layer wraps that decision with the HOST-
7
+ // SIDE execution: when the kernel returns `Invoke`, we run the actual
8
+ // tool; when it returns Denied/NotFound/BadArgs, we surface the reason.
9
+ /**
10
+ * In-process tool dispatcher. Use for harnesses that register tool
11
+ * handlers directly in TS (host adapter wraps these).
12
+ */
13
+ export class ToolDispatcher {
14
+ handlers = new Map();
15
+ key(server, tool) {
16
+ return `${server}/${tool}`;
17
+ }
18
+ register(server, tool, handler) {
19
+ this.handlers.set(this.key(server, tool), handler);
20
+ }
21
+ has(server, tool) {
22
+ return this.handlers.has(this.key(server, tool));
23
+ }
24
+ /**
25
+ * Execute the dispatch. Returns the structured outcome rather than
26
+ * throwing so callers can branch on the result type.
27
+ */
28
+ async dispatch(opts, nowUnix = Math.floor(Date.now() / 1000)) {
29
+ if (!this.has(opts.server, opts.tool)) {
30
+ return { kind: 'not-found', server: opts.server, tool: opts.tool };
31
+ }
32
+ if (typeof opts.args !== 'object' || opts.args === null || Array.isArray(opts.args)) {
33
+ return { kind: 'bad-args', reason: 'args must be a non-array object' };
34
+ }
35
+ const cap = `tool.invoke.${opts.server}.${opts.tool}`;
36
+ const allowed = opts.claims.some(c => capabilityMatches(c.capability, cap) &&
37
+ resourceMatches(c.resource, opts.resource) &&
38
+ c.expires_at > nowUnix);
39
+ if (!allowed) {
40
+ return { kind: 'denied', reason: `no claim authorises ${cap}` };
41
+ }
42
+ try {
43
+ const handler = this.handlers.get(this.key(opts.server, opts.tool));
44
+ const output = await handler(opts.args);
45
+ return { kind: 'result', output };
46
+ }
47
+ catch (err) {
48
+ return { kind: 'denied', reason: err instanceof Error ? err.message : String(err) };
49
+ }
50
+ }
51
+ }
52
+ function capabilityMatches(granted, requested) {
53
+ if (granted === '*' || granted === requested)
54
+ return true;
55
+ if (granted.endsWith('.*')) {
56
+ const prefix = granted.slice(0, -2);
57
+ return requested === prefix || (requested.startsWith(prefix + '.'));
58
+ }
59
+ return false;
60
+ }
61
+ function resourceMatches(granted, requested) {
62
+ if (granted === undefined)
63
+ return true;
64
+ if (requested === undefined)
65
+ return false;
66
+ if (granted === requested || granted === '*')
67
+ return true;
68
+ if (granted.endsWith('/*')) {
69
+ const prefix = granted.slice(0, -2);
70
+ return requested.startsWith(prefix + '/');
71
+ }
72
+ return false;
73
+ }
74
+ //# sourceMappingURL=dispatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ export type { McpServerSpec, ToolSpec, AgentSpec, HookSpec, HarnessSpec, HostAdapter } from './types.js';
2
+ export interface KernelInfo {
3
+ version: string;
4
+ git_sha: string;
5
+ target: string;
6
+ }
7
+ interface KernelBackend {
8
+ kernelInfo(): KernelInfo;
9
+ mcpValidate(specJson: string): string | null;
10
+ version(): string;
11
+ backend: 'native' | 'wasm' | 'js';
12
+ }
13
+ /**
14
+ * Load the kernel. native > wasm > pure-JS. The JS backend is the floor, so
15
+ * this never rejects with a missing-module error. Cached.
16
+ */
17
+ export declare function loadKernel(): Promise<KernelBackend>;
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzG,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,aAAa;IACrB,UAAU,IAAI,UAAU,CAAC;IACzB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC7C,OAAO,IAAI,MAAM,CAAC;IAClB,OAAO,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAC;CACnC;AAuGD;;;GAGG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,aAAa,CAAC,CAKzD"}
package/dist/index.js ADDED
@@ -0,0 +1,127 @@
1
+ // SPDX-License-Identifier: MIT
2
+ //
3
+ // @metaharness/kernel runtime resolver. Per ADR-002a, the kernel ships as Rust
4
+ // source compiled to wasm + per-platform NAPI-RS for speed. BUT neither of
5
+ // those is guaranteed to be present in a plain `npm install` (the wasm pkg/
6
+ // is built by a separate CI job; the NAPI platform packages are optional).
7
+ // Without a fallback, `loadKernel()` threw ERR_MODULE_NOT_FOUND and every
8
+ // generated harness was dead on arrival. This module therefore ALWAYS has a
9
+ // third backend: a dependency-free pure-JS implementation. native > wasm > js,
10
+ // but js is the floor — the kernel is always loadable. (ADR-002a §fallback.)
11
+ import { createRequire } from 'node:module';
12
+ let _cached = null;
13
+ async function loadNative() {
14
+ try {
15
+ const plat = `${process.platform}-${process.arch}`;
16
+ const map = {
17
+ 'darwin-arm64': '@metaharness/kernel-darwin-arm64',
18
+ 'darwin-x64': '@metaharness/kernel-darwin-x64',
19
+ 'linux-x64': '@metaharness/kernel-linux-x64-gnu',
20
+ 'linux-arm64': '@metaharness/kernel-linux-arm64-gnu',
21
+ 'win32-x64': '@metaharness/kernel-win32-x64-msvc',
22
+ };
23
+ const pkg = map[plat];
24
+ if (!pkg)
25
+ return null;
26
+ const mod = await import(pkg);
27
+ return {
28
+ kernelInfo: () => mod.kernelInfo(),
29
+ mcpValidate: (s) => mod.mcpValidate(s) ?? null,
30
+ version: () => mod.version(),
31
+ backend: 'native',
32
+ };
33
+ }
34
+ catch {
35
+ return null;
36
+ }
37
+ }
38
+ async function loadWasm() {
39
+ try {
40
+ // @ts-ignore — generated by `wasm-pack build` into ../pkg/, absent during
41
+ // a TS-only build (the WASM CI job builds it separately). A miss is
42
+ // non-fatal: we fall through to the pure-JS backend below.
43
+ const mod = await import('../pkg/ruflo_kernel_wasm.js');
44
+ if (typeof mod.default === 'function') {
45
+ await mod.default();
46
+ }
47
+ return {
48
+ kernelInfo: () => mod.kernelInfo(),
49
+ mcpValidate: (s) => mod.mcpValidate(s) ?? null,
50
+ version: () => mod.version(),
51
+ backend: 'wasm',
52
+ };
53
+ }
54
+ catch {
55
+ return null;
56
+ }
57
+ }
58
+ /**
59
+ * The kernel's own version, read from its package.json. Cached. Falls back to
60
+ * '0.0.0' only if the package.json is somehow unreadable (never expected).
61
+ */
62
+ let _version = null;
63
+ function kernelVersion() {
64
+ if (_version)
65
+ return _version;
66
+ try {
67
+ const require = createRequire(import.meta.url);
68
+ // dist/index.js → ../package.json
69
+ _version = require('../package.json').version ?? '0.0.0';
70
+ }
71
+ catch {
72
+ _version = '0.0.0';
73
+ }
74
+ return _version;
75
+ }
76
+ /**
77
+ * Pure-JS kernel backend — zero native/wasm dependencies, always available.
78
+ * It reimplements the load-bearing kernel surface (kernelInfo / version /
79
+ * mcpValidate) in TypeScript so a harness installed from npm works with no
80
+ * compiled artifacts. The validation rules mirror crates/kernel/src/mcp.rs
81
+ * exactly (server name non-empty; command XOR url) so behaviour is identical
82
+ * whether the native, wasm, or js backend answers.
83
+ */
84
+ function loadJs() {
85
+ return {
86
+ kernelInfo: () => ({
87
+ version: kernelVersion(),
88
+ git_sha: 'js',
89
+ target: `${process.platform}-${process.arch}`,
90
+ }),
91
+ version: () => kernelVersion(),
92
+ mcpValidate: (specJson) => {
93
+ let spec;
94
+ try {
95
+ spec = JSON.parse(specJson);
96
+ }
97
+ catch (e) {
98
+ // Mirror the NAPI binding, which throws on unparseable spec JSON.
99
+ throw new Error(`invalid spec json: ${e.message}`);
100
+ }
101
+ // Rules, byte-for-byte from crates/kernel/src/mcp.rs::validate.
102
+ if (typeof spec.name !== 'string' || spec.name.length === 0) {
103
+ return 'server name is empty';
104
+ }
105
+ const hasCommand = Array.isArray(spec.command) && spec.command.length > 0;
106
+ const hasUrl = typeof spec.url === 'string' && spec.url.length > 0;
107
+ if (hasCommand && hasUrl)
108
+ return 'command and url are mutually exclusive';
109
+ if (!hasCommand && !hasUrl)
110
+ return 'either command or url must be set';
111
+ return null;
112
+ },
113
+ backend: 'js',
114
+ };
115
+ }
116
+ /**
117
+ * Load the kernel. native > wasm > pure-JS. The JS backend is the floor, so
118
+ * this never rejects with a missing-module error. Cached.
119
+ */
120
+ export async function loadKernel() {
121
+ if (_cached)
122
+ return _cached;
123
+ const native = await loadNative();
124
+ _cached = native ?? (await loadWasm()) ?? loadJs();
125
+ return _cached;
126
+ }
127
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { MemoryHit } from './memory.js';
2
+ export interface RvfBackend {
3
+ /** Insert a vector into the index. */
4
+ insert(id: string, embedding: number[], namespace?: string): Promise<void>;
5
+ /** Search by embedding similarity. */
6
+ search(embedding: number[], k: number, namespace?: string): Promise<MemoryHit[]>;
7
+ /** Total items currently indexed. */
8
+ size(): Promise<number>;
9
+ /** Persist + flush. */
10
+ flush(): Promise<void>;
11
+ }
12
+ /** Is the RVF package installed and importable in the current process? */
13
+ export declare function isRvfAvailable(): Promise<boolean>;
14
+ /**
15
+ * Create an RVF-backed backend. Returns null if RVF isn't installed —
16
+ * caller falls back to the in-process HNSW.
17
+ */
18
+ export declare function createRvfBackend(opts: {
19
+ dimensions: number;
20
+ metric?: 'cosine' | 'l2';
21
+ }): Promise<RvfBackend | null>;
22
+ //# sourceMappingURL=memory-rvf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-rvf.d.ts","sourceRoot":"","sources":["../src/memory-rvf.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,WAAW,UAAU;IACzB,sCAAsC;IACtC,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,sCAAsC;IACtC,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IACjF,qCAAqC;IACrC,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IACxB,uBAAuB;IACvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAiCD,0EAA0E;AAC1E,wBAAsB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAEvD;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;CAC1B,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CA2C7B"}
@@ -0,0 +1,87 @@
1
+ // SPDX-License-Identifier: MIT
2
+ //
3
+ // memory-rvf — graceful-fallback wrapper over @ruvector/rvf
4
+ // (https://www.npmjs.com/package/@ruvector/rvf).
5
+ //
6
+ // RVF is "RuVector Format — unified TypeScript SDK for vector intelligence":
7
+ // HNSW-indexed binary vector format with SIMD, dual-target (TypeScript
8
+ // runtime + optional @ruvector/rvf-wasm). When the user has RVF installed
9
+ // AND wants RVF-backed memory storage, the kernel uses it; otherwise the
10
+ // memory subsystem keeps using its plain in-process HNSW.
11
+ //
12
+ // RVF is declared as an OPTIONAL peer dep so the kernel doesn't bloat
13
+ // install size for users who don't need it. The pairing matters most
14
+ // for RVM-deployed harnesses — RVM's wasm guest can run rvf-wasm
15
+ // inside the partition for hardware-isolated vector storage.
16
+ let _rvf;
17
+ async function loadRvf() {
18
+ if (_rvf !== undefined)
19
+ return _rvf;
20
+ try {
21
+ // @ts-ignore — @ruvector/rvf is declared as an OPTIONAL peer
22
+ // dependency, so a fresh CI install without it must build cleanly.
23
+ // The graceful-fallback path returns null when the package is absent.
24
+ _rvf = await import('@ruvector/rvf');
25
+ return _rvf;
26
+ }
27
+ catch {
28
+ _rvf = null;
29
+ return null;
30
+ }
31
+ }
32
+ /** Is the RVF package installed and importable in the current process? */
33
+ export async function isRvfAvailable() {
34
+ return (await loadRvf()) !== null;
35
+ }
36
+ /**
37
+ * Create an RVF-backed backend. Returns null if RVF isn't installed —
38
+ * caller falls back to the in-process HNSW.
39
+ */
40
+ export async function createRvfBackend(opts) {
41
+ const mod = await loadRvf();
42
+ if (!mod)
43
+ return null;
44
+ const createIndex = mod.createIndex ?? mod.default?.createIndex;
45
+ if (typeof createIndex !== 'function')
46
+ return null;
47
+ const indexByNs = new Map();
48
+ const ensure = async (ns) => {
49
+ let idx = indexByNs.get(ns);
50
+ if (!idx) {
51
+ idx = await createIndex({ dimensions: opts.dimensions, metric: opts.metric ?? 'cosine' });
52
+ indexByNs.set(ns, idx);
53
+ }
54
+ return idx;
55
+ };
56
+ return {
57
+ async insert(id, embedding, namespace = 'default') {
58
+ const idx = await ensure(namespace);
59
+ await idx.add(id, embedding);
60
+ },
61
+ async search(embedding, k, namespace = 'default') {
62
+ const idx = await ensure(namespace);
63
+ const raw = await idx.search(embedding, k);
64
+ return raw.map(r => ({
65
+ id: r.id,
66
+ score: r.score,
67
+ decayedScore: r.score, // memory.rankWithDecay applies decay separately
68
+ namespace,
69
+ }));
70
+ },
71
+ async size() {
72
+ let total = 0;
73
+ for (const idx of indexByNs.values()) {
74
+ const count = await (idx.count?.() ?? idx.size?.() ?? Promise.resolve(0));
75
+ total += count ?? 0;
76
+ }
77
+ return total;
78
+ },
79
+ async flush() {
80
+ for (const idx of indexByNs.values()) {
81
+ if (typeof idx.flush === 'function')
82
+ await idx.flush();
83
+ }
84
+ },
85
+ };
86
+ }
87
+ //# sourceMappingURL=memory-rvf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-rvf.js","sourceRoot":"","sources":["../src/memory-rvf.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ export interface MemoryHit {
2
+ /** Memory entry id. */
3
+ id: string;
4
+ /** Raw cosine similarity (0..1) — what HNSW returned. */
5
+ score: number;
6
+ /**
7
+ * Decay-weighted score. When emergent-time isn't loaded, equals `score`.
8
+ * When loaded, multiplied by the AgenticClock weight for the entry's age.
9
+ */
10
+ decayedScore: number;
11
+ /** Namespace the hit lives in. */
12
+ namespace: string;
13
+ /** When this entry was stored (ms since epoch). */
14
+ storedAt?: number;
15
+ }
16
+ export interface DecayConfig {
17
+ /** Reference timestamp for "now" (ms). Defaults to Date.now() at query time. */
18
+ now?: number;
19
+ /** When true, returns hits ranked by decayedScore. When false, by score. */
20
+ useDecay?: boolean;
21
+ /**
22
+ * Half-life in milliseconds — at this age, decay weight is 0.5. The
23
+ * AgenticClock translates this into a six-channel structural-proper-time
24
+ * estimate; we surface only the resulting weight here.
25
+ */
26
+ halfLifeMs?: number;
27
+ }
28
+ /**
29
+ * Rank a list of raw HNSW hits, applying AgenticClock decay weights when
30
+ * `useDecay` is true and the emergent-time package is available.
31
+ *
32
+ * Returns a NEW array sorted descending by decayedScore (when useDecay=true)
33
+ * or score (when false).
34
+ */
35
+ export declare function rankWithDecay(hits: MemoryHit[], config?: DecayConfig): Promise<MemoryHit[]>;
36
+ /**
37
+ * Change-point trigger for the DISTILL phase. Feeds a stream of
38
+ * trajectory-success scores into PageHinkleyDetector; when the detector
39
+ * fires, the intel pipeline kicks DISTILL.
40
+ *
41
+ * Returns a callable that consumes scores one at a time.
42
+ */
43
+ export declare function distillTrigger(opts?: {
44
+ threshold?: number;
45
+ delta?: number;
46
+ }): Promise<(score: number) => {
47
+ changePoint: boolean;
48
+ magnitude: number;
49
+ }>;
50
+ /**
51
+ * Linear decay function for tests / fallback paths that need a simple
52
+ * deterministic weight without loading emergent-time.
53
+ */
54
+ export declare function linearDecay(ageMs: number, halfLifeMs: number): number;
55
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAsBA,MAAM,WAAW,SAAS;IACxB,uBAAuB;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,gFAAgF;IAChF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA6BD;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,SAAS,EAAE,EACjB,MAAM,GAAE,WAAgB,GACvB,OAAO,CAAC,SAAS,EAAE,CAAC,CAyBtB;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAC9F,CAAC,KAAK,EAAE,MAAM,KAAK;IAAE,WAAW,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAC/D,CASA;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAIrE"}
package/dist/memory.js ADDED
@@ -0,0 +1,100 @@
1
+ // SPDX-License-Identifier: MIT
2
+ //
3
+ // Memory subsystem TS bridge.
4
+ //
5
+ // Per ADR-006, the kernel exposes the memory BRIDGE API. The actual vector
6
+ // store is AgentDB-backed; the kernel adds DECAY-WEIGHTED scoring on top of
7
+ // raw cosine similarity, driven by `@ruvector/emergent-time@0.1.0`.
8
+ //
9
+ // The integration follows the per-API mapping table in ADR-006:
10
+ // - AgenticClock -> per-memory decay weight (HNSW score multiplier)
11
+ // - WindowedDeltaClock -> trajectory-step weighting (intel pipeline)
12
+ // - PageHinkleyDetector -> change-point trigger for DISTILL phase firing
13
+ // - LearnedWeights -> reserved for self-evolution (iter 7+, ADR-014)
14
+ //
15
+ // All four exports come from the same npm package the user shipped
16
+ // today: https://www.npmjs.com/package/@ruvector/emergent-time
17
+ //
18
+ // Honesty caveat (from the @ruvector/emergent-time README): the SDK is
19
+ // "diagnostic signal, no proven early-warning lead over a fair baseline".
20
+ // So we gate the decay-weighted path behind a feature flag and ALWAYS
21
+ // preserve the raw cosine score so callers can compare.
22
+ let _emergent;
23
+ async function loadEmergent() {
24
+ if (_emergent !== undefined)
25
+ return _emergent;
26
+ try {
27
+ const mod = await import('@ruvector/emergent-time');
28
+ // Probe-construct an AgenticClock to confirm WASM is actually initialised.
29
+ // The dynamic-import resolves the JS shim even when the underlying WASM
30
+ // bindings haven't been bootstrapped, so a present-module check isn't
31
+ // enough — the constructor throws on first use ("Cannot read properties
32
+ // of undefined (reading 'agenticclock_new')"). Probe + discard catches
33
+ // that case and routes the caller to its raw-score fallback.
34
+ new mod.AgenticClock({ halfLifeMs: 1000 });
35
+ _emergent = mod;
36
+ return mod;
37
+ }
38
+ catch {
39
+ _emergent = null;
40
+ return null;
41
+ }
42
+ }
43
+ /**
44
+ * Rank a list of raw HNSW hits, applying AgenticClock decay weights when
45
+ * `useDecay` is true and the emergent-time package is available.
46
+ *
47
+ * Returns a NEW array sorted descending by decayedScore (when useDecay=true)
48
+ * or score (when false).
49
+ */
50
+ export async function rankWithDecay(hits, config = {}) {
51
+ const now = config.now ?? Date.now();
52
+ const useDecay = config.useDecay ?? true;
53
+ const halfLifeMs = config.halfLifeMs ?? 7 * 24 * 60 * 60 * 1000; // 7 days
54
+ if (!useDecay) {
55
+ return [...hits].sort((a, b) => b.score - a.score);
56
+ }
57
+ const emergent = await loadEmergent();
58
+ if (!emergent) {
59
+ // Graceful fallback — return raw scores in `decayedScore` so callers
60
+ // don't have to special-case the absence of emergent-time.
61
+ return [...hits].map(h => ({ ...h, decayedScore: h.score }))
62
+ .sort((a, b) => b.decayedScore - a.decayedScore);
63
+ }
64
+ const clock = new emergent.AgenticClock({ halfLifeMs });
65
+ const ranked = hits.map(h => {
66
+ const ageMs = h.storedAt !== undefined ? Math.max(0, now - h.storedAt) : 0;
67
+ const weight = clock.weight(ageMs);
68
+ return { ...h, decayedScore: h.score * weight };
69
+ });
70
+ ranked.sort((a, b) => b.decayedScore - a.decayedScore);
71
+ return ranked;
72
+ }
73
+ /**
74
+ * Change-point trigger for the DISTILL phase. Feeds a stream of
75
+ * trajectory-success scores into PageHinkleyDetector; when the detector
76
+ * fires, the intel pipeline kicks DISTILL.
77
+ *
78
+ * Returns a callable that consumes scores one at a time.
79
+ */
80
+ export async function distillTrigger(opts = {}) {
81
+ const emergent = await loadEmergent();
82
+ if (!emergent) {
83
+ // Fallback: never fire. Caller's DISTILL phase still runs on its
84
+ // threshold-based gate.
85
+ return (_score) => ({ changePoint: false, magnitude: 0 });
86
+ }
87
+ const detector = new emergent.PageHinkleyDetector(opts);
88
+ return (score) => detector.feed(score);
89
+ }
90
+ /**
91
+ * Linear decay function for tests / fallback paths that need a simple
92
+ * deterministic weight without loading emergent-time.
93
+ */
94
+ export function linearDecay(ageMs, halfLifeMs) {
95
+ if (ageMs <= 0)
96
+ return 1;
97
+ const halves = ageMs / halfLifeMs;
98
+ return Math.pow(0.5, halves);
99
+ }
100
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ export type RoutingTier = 'codemod' | 'small' | 'frontier';
2
+ export interface RoutingHistoryEntry {
3
+ /** Tier that was chosen. */
4
+ tier: RoutingTier;
5
+ /** Did the call succeed (e.g. task completed)? */
6
+ success: boolean;
7
+ /** Latency in ms. */
8
+ latencyMs: number;
9
+ /** Approximate cost in USD. */
10
+ costUsd: number;
11
+ /** Optional task fingerprint (semantic class). */
12
+ taskFingerprint?: string;
13
+ }
14
+ export interface SelfEvolvingConfig {
15
+ /** When true, applies learned weights. When false, passes through. */
16
+ enabled: boolean;
17
+ /** Reward signal weights. Defaults sum to 1.0. */
18
+ rewardMix?: {
19
+ successWeight: number;
20
+ latencyWeight: number;
21
+ costWeight: number;
22
+ };
23
+ /** Bias toward small-tier (saving budget) — multiplier on small's weight. */
24
+ smallTierBias?: number;
25
+ }
26
+ /**
27
+ * Compute a reward in [0, 1] from a single routing outcome.
28
+ *
29
+ * - success contributes successWeight directly (1 if succeeded, 0 if not)
30
+ * - latency contributes latencyWeight scaled by 1/(1 + ms/1000) — saturates
31
+ * - cost contributes costWeight scaled by 1/(1 + usd*1000) — saturates
32
+ */
33
+ export declare function computeReward(entry: RoutingHistoryEntry, config: SelfEvolvingConfig): number;
34
+ /**
35
+ * A learned-weights router. Wraps the kernel router's decision with a
36
+ * post-hoc weight applied to each tier; weights update from outcomes.
37
+ *
38
+ * When `config.enabled === false`, this is a pure pass-through.
39
+ */
40
+ export declare class SelfEvolvingRouter {
41
+ private config;
42
+ private weights;
43
+ private history;
44
+ private impl;
45
+ constructor(config: SelfEvolvingConfig);
46
+ ensureLoaded(): Promise<void>;
47
+ /**
48
+ * Record an outcome and update learned weights.
49
+ * Returns the reward used (for tests/telemetry).
50
+ */
51
+ recordOutcome(entry: RoutingHistoryEntry): Promise<number>;
52
+ /**
53
+ * Get the current weight for a tier. Higher = more preferred.
54
+ */
55
+ weightFor(tier: RoutingTier): number;
56
+ /**
57
+ * Re-rank a tier shortlist by current weights.
58
+ * Returns tiers ordered most preferred first.
59
+ */
60
+ reRank(tiers: RoutingTier[]): RoutingTier[];
61
+ history_(): readonly RoutingHistoryEntry[];
62
+ }
63
+ //# sourceMappingURL=self-evolution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"self-evolution.d.ts","sourceRoot":"","sources":["../src/self-evolution.ts"],"names":[],"mappings":"AAgBA,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,UAAU,CAAC;AAE3D,MAAM,WAAW,mBAAmB;IAClC,4BAA4B;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,kDAAkD;IAClD,OAAO,EAAE,OAAO,CAAC;IACjB,qBAAqB;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,+BAA+B;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB;IACjC,sEAAsE;IACtE,OAAO,EAAE,OAAO,CAAC;IACjB,kDAAkD;IAClD,SAAS,CAAC,EAAE;QACV,aAAa,EAAE,MAAM,CAAC;QACtB,aAAa,EAAE,MAAM,CAAC;QACtB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAgCD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,mBAAmB,EAAE,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAY5F;AAED;;;;;GAKG;AACH,qBAAa,kBAAkB;IAKjB,OAAO,CAAC,MAAM;IAJ1B,OAAO,CAAC,OAAO,CAAsE;IACrF,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,IAAI,CAAgI;gBAExH,MAAM,EAAE,kBAAkB;IAExC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IASnC;;;OAGG;IACG,aAAa,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC;IAkChE;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM;IAIpC;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE;IAI3C,QAAQ,IAAI,SAAS,mBAAmB,EAAE;CAG3C"}
@@ -0,0 +1,138 @@
1
+ // SPDX-License-Identifier: MIT
2
+ //
3
+ // Self-evolving routing. Wraps `@ruvector/emergent-time`'s LearnedWeights
4
+ // over the kernel's 3-tier router so a harness can ADAPT its routing
5
+ // decisions over time based on the outcomes of past calls.
6
+ //
7
+ // Per ADR-014 (Self-evolution + federation), this is the "exotic" mode —
8
+ // off by default, opt-in. When enabled, every routing decision feeds back
9
+ // a reward signal (success/failure + latency + cost), and the LearnedWeights
10
+ // inference shifts future decisions toward whichever tier worked best for
11
+ // similar tasks.
12
+ //
13
+ // Honesty caveat from the @ruvector/emergent-time README applies here:
14
+ // "diagnostic signal, no proven early-warning lead over a fair baseline".
15
+ // The self-evolving path is gated behind explicit opt-in for that reason.
16
+ let _emergent;
17
+ async function loadEmergent() {
18
+ if (_emergent !== undefined)
19
+ return _emergent;
20
+ try {
21
+ const mod = await import('@ruvector/emergent-time');
22
+ // Probe-construct + verify the API contract holds. Catches both:
23
+ // (1) WASM not initialised — constructor throws on `learnedweights_new`
24
+ // (2) API drift — module loaded but `.update` no longer on the prototype
25
+ // In either case, fall back to the local EMA path so tests + runtime see
26
+ // a consistent "graceful absent" signal.
27
+ const probe = new mod.LearnedWeights({ tiers: ['probe'] });
28
+ if (typeof probe.update !== 'function' || typeof probe.weights !== 'function') {
29
+ throw new Error('LearnedWeights API surface drifted');
30
+ }
31
+ _emergent = mod;
32
+ return mod;
33
+ }
34
+ catch {
35
+ _emergent = null;
36
+ return null;
37
+ }
38
+ }
39
+ /**
40
+ * Compute a reward in [0, 1] from a single routing outcome.
41
+ *
42
+ * - success contributes successWeight directly (1 if succeeded, 0 if not)
43
+ * - latency contributes latencyWeight scaled by 1/(1 + ms/1000) — saturates
44
+ * - cost contributes costWeight scaled by 1/(1 + usd*1000) — saturates
45
+ */
46
+ export function computeReward(entry, config) {
47
+ const mix = config.rewardMix ?? { successWeight: 0.5, latencyWeight: 0.3, costWeight: 0.2 };
48
+ const successComponent = entry.success ? 1 : 0;
49
+ const latencyComponent = 1 / (1 + entry.latencyMs / 1000);
50
+ const costComponent = 1 / (1 + entry.costUsd * 1000);
51
+ const total = mix.successWeight * successComponent +
52
+ mix.latencyWeight * latencyComponent +
53
+ mix.costWeight * costComponent;
54
+ // Normalise to [0, 1] in case the weights don't sum to 1.
55
+ const denominator = mix.successWeight + mix.latencyWeight + mix.costWeight;
56
+ return total / denominator;
57
+ }
58
+ /**
59
+ * A learned-weights router. Wraps the kernel router's decision with a
60
+ * post-hoc weight applied to each tier; weights update from outcomes.
61
+ *
62
+ * When `config.enabled === false`, this is a pure pass-through.
63
+ */
64
+ export class SelfEvolvingRouter {
65
+ config;
66
+ weights = { codemod: 1, small: 1, frontier: 1 };
67
+ history = [];
68
+ impl = null;
69
+ constructor(config) {
70
+ this.config = config;
71
+ }
72
+ async ensureLoaded() {
73
+ if (!this.config.enabled)
74
+ return;
75
+ if (this.impl)
76
+ return;
77
+ const emergent = await loadEmergent();
78
+ if (emergent) {
79
+ this.impl = new emergent.LearnedWeights({ tiers: ['codemod', 'small', 'frontier'] });
80
+ }
81
+ }
82
+ /**
83
+ * Record an outcome and update learned weights.
84
+ * Returns the reward used (for tests/telemetry).
85
+ */
86
+ async recordOutcome(entry) {
87
+ this.history.push(entry);
88
+ if (!this.config.enabled)
89
+ return 0;
90
+ await this.ensureLoaded();
91
+ const reward = computeReward(entry, this.config);
92
+ if (this.impl) {
93
+ this.impl.update(entry.tier, reward);
94
+ const w = this.impl.weights();
95
+ this.weights = {
96
+ codemod: w.codemod ?? 1,
97
+ small: w.small ?? 1,
98
+ frontier: w.frontier ?? 1,
99
+ };
100
+ }
101
+ else {
102
+ // Local exponential moving average fallback when emergent-time
103
+ // isn't installed. Smaller learning rate so single bad runs don't
104
+ // crater a tier.
105
+ //
106
+ // Important: the EMA target is `reward * 2`, not `reward`. computeReward
107
+ // returns values in [0, 1] where 0.5 is "neutral / break-even". Mapping
108
+ // to [0, 2] keeps the initial weight of 1.0 as the neutral baseline:
109
+ // successful tiers pull above 1.0, failed tiers pull below, untouched
110
+ // tiers stay at 1.0. Without this rescale, ALL tiers slowly drift below
111
+ // 1.0 and untouched tiers always win — silently breaking re-ranking.
112
+ const lr = 0.1;
113
+ const target = reward * 2;
114
+ this.weights[entry.tier] = (1 - lr) * this.weights[entry.tier] + lr * target;
115
+ }
116
+ if (this.config.smallTierBias) {
117
+ this.weights.small *= this.config.smallTierBias;
118
+ }
119
+ return reward;
120
+ }
121
+ /**
122
+ * Get the current weight for a tier. Higher = more preferred.
123
+ */
124
+ weightFor(tier) {
125
+ return this.weights[tier];
126
+ }
127
+ /**
128
+ * Re-rank a tier shortlist by current weights.
129
+ * Returns tiers ordered most preferred first.
130
+ */
131
+ reRank(tiers) {
132
+ return [...tiers].sort((a, b) => this.weights[b] - this.weights[a]);
133
+ }
134
+ history_() {
135
+ return this.history;
136
+ }
137
+ }
138
+ //# sourceMappingURL=self-evolution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"self-evolution.js","sourceRoot":"","sources":["../src/self-evolution.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ export interface TrajectoryRecord {
2
+ /** ISO-8601 timestamp. */
3
+ ts: string;
4
+ /** Pipeline phase. */
5
+ phase: 'Retrieve' | 'Judge' | 'Distill' | 'Consolidate';
6
+ /** Outcome — Success/Skip/Fail in lowercase for JSONL compactness. */
7
+ outcome: 'success' | 'skip' | 'fail';
8
+ /** Free-form output. */
9
+ output?: unknown;
10
+ }
11
+ export declare class TrajectoryStore {
12
+ private path;
13
+ constructor(path: string);
14
+ append(record: TrajectoryRecord): Promise<void>;
15
+ readAll(): Promise<TrajectoryRecord[]>;
16
+ /** Rotate the file if it exceeds maxBytes. Old data goes to `<path>.1`. */
17
+ rotateIfLarger(maxBytes: number): Promise<boolean>;
18
+ size(): Promise<number>;
19
+ }
20
+ //# sourceMappingURL=trajectory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trajectory.d.ts","sourceRoot":"","sources":["../src/trajectory.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,gBAAgB;IAC/B,0BAA0B;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,sBAAsB;IACtB,KAAK,EAAE,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,aAAa,CAAC;IACxD,sEAAsE;IACtE,OAAO,EAAE,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;IACrC,wBAAwB;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,eAAe;IACd,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,MAAM;IAE1B,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/C,OAAO,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAM5C,2EAA2E;IACrE,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IASlD,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;CAI9B"}
@@ -0,0 +1,43 @@
1
+ // SPDX-License-Identifier: MIT
2
+ //
3
+ // Trajectory persistence — JSONL append-only store for the intel pipeline's
4
+ // RETRIEVE → JUDGE → DISTILL → CONSOLIDATE phases.
5
+ //
6
+ // Append-only: each record is one line of JSON. Reading is a streaming
7
+ // line-by-line parse so unbounded growth doesn't blow up memory. Optional
8
+ // rotation cap (records-old-than-N or file-size-greater-than-M) keeps
9
+ // the store bounded.
10
+ import { appendFile, readFile, stat, rename, writeFile } from 'node:fs/promises';
11
+ import { existsSync } from 'node:fs';
12
+ export class TrajectoryStore {
13
+ path;
14
+ constructor(path) {
15
+ this.path = path;
16
+ }
17
+ async append(record) {
18
+ await appendFile(this.path, JSON.stringify(record) + '\n', 'utf-8');
19
+ }
20
+ async readAll() {
21
+ if (!existsSync(this.path))
22
+ return [];
23
+ const raw = await readFile(this.path, 'utf-8');
24
+ return raw.split('\n').filter(Boolean).map(l => JSON.parse(l));
25
+ }
26
+ /** Rotate the file if it exceeds maxBytes. Old data goes to `<path>.1`. */
27
+ async rotateIfLarger(maxBytes) {
28
+ if (!existsSync(this.path))
29
+ return false;
30
+ const s = await stat(this.path);
31
+ if (s.size <= maxBytes)
32
+ return false;
33
+ await rename(this.path, this.path + '.1');
34
+ await writeFile(this.path, '', 'utf-8');
35
+ return true;
36
+ }
37
+ async size() {
38
+ if (!existsSync(this.path))
39
+ return 0;
40
+ return (await stat(this.path)).size;
41
+ }
42
+ }
43
+ //# sourceMappingURL=trajectory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trajectory.js","sourceRoot":"","sources":["../src/trajectory.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,EAAE;AACF,4EAA4E;AAC5E,mDAAmD;AACnD,EAAE;AACF,uEAAuE;AACvE,0EAA0E;AAC1E,sEAAsE;AACtE,qBAAqB;AAErB,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAarC,MAAM,OAAO,eAAe;IACN;IAApB,YAAoB,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;IAAG,CAAC;IAEpC,KAAK,CAAC,MAAM,CAAC,MAAwB;QACnC,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;IACtE,CAAC;IAED,KAAK,CAAC,OAAO;QACX,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,EAAE,CAAC;QACtC,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC/C,OAAO,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAqB,CAAC,CAAC;IACrF,CAAC;IAED,2EAA2E;IAC3E,KAAK,CAAC,cAAc,CAAC,QAAgB;QACnC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC;QACzC,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,CAAC,CAAC,IAAI,IAAI,QAAQ;YAAE,OAAO,KAAK,CAAC;QACrC,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;QAC1C,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;QACxC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,CAAC,CAAC;QACrC,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACtC,CAAC;CACF"}
@@ -0,0 +1,40 @@
1
+ export interface McpServerSpec {
2
+ name: string;
3
+ command?: string[];
4
+ url?: string;
5
+ env?: Array<[string, string]>;
6
+ }
7
+ export interface ToolSpec {
8
+ name: string;
9
+ description?: string;
10
+ inputSchema?: Record<string, unknown>;
11
+ }
12
+ export interface AgentSpec {
13
+ name: string;
14
+ systemPrompt?: string;
15
+ }
16
+ export interface HookSpec {
17
+ event: string;
18
+ matcher?: string;
19
+ handler: string;
20
+ }
21
+ export interface HarnessSpec {
22
+ name: string;
23
+ description?: string;
24
+ systemPrompt?: string;
25
+ mcpServers?: McpServerSpec[];
26
+ tools?: ToolSpec[];
27
+ agents?: AgentSpec[];
28
+ hooks?: HookSpec[];
29
+ permissions?: {
30
+ allow?: string[];
31
+ deny?: string[];
32
+ };
33
+ statusLine?: string;
34
+ }
35
+ export interface HostAdapter {
36
+ name: string;
37
+ /** Return a map of file-path -> file-content for the host's config. */
38
+ generateConfig(spec: HarnessSpec): Record<string, string>;
39
+ }
40
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,aAAa,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;IACrB,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB,WAAW,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,cAAc,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC3D"}
package/dist/types.js ADDED
@@ -0,0 +1,7 @@
1
+ // SPDX-License-Identifier: MIT
2
+ //
3
+ // Shared types consumed by the host adapter packages. Defined separately
4
+ // from the runtime loader so adapters can `import type` without pulling
5
+ // the wasm/native loader into their bundle.
6
+ export {};
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,EAAE;AACF,yEAAyE;AACzE,wEAAwE;AACxE,4CAA4C"}
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "@metaharness/kernel",
3
+ "version": "0.1.0",
4
+ "description": "Cross-platform kernel for the agent-harness-generator — wasm primary, NAPI-RS native fallback",
5
+ "homepage": "https://github.com/ruvnet/agent-harness-generator",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/ruvnet/agent-harness-generator.git",
9
+ "directory": "packages/kernel-js"
10
+ },
11
+ "license": "MIT",
12
+ "author": "rUv <ruv@ruv.net>",
13
+ "type": "module",
14
+ "main": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.js"
20
+ },
21
+ "./memory": {
22
+ "types": "./dist/memory.d.ts",
23
+ "import": "./dist/memory.js"
24
+ },
25
+ "./memory-rvf": {
26
+ "types": "./dist/memory-rvf.d.ts",
27
+ "import": "./dist/memory-rvf.js"
28
+ },
29
+ "./dispatch": {
30
+ "types": "./dist/dispatch.d.ts",
31
+ "import": "./dist/dispatch.js"
32
+ }
33
+ },
34
+ "files": [
35
+ "dist/**",
36
+ "pkg/**",
37
+ "README.md",
38
+ "LICENSE"
39
+ ],
40
+ "scripts": {
41
+ "build": "tsc",
42
+ "test": "vitest run",
43
+ "lint": "tsc --noEmit"
44
+ },
45
+ "keywords": [
46
+ "agent-harness",
47
+ "mcp",
48
+ "wasm",
49
+ "kernel",
50
+ "ruflo"
51
+ ],
52
+ "publishConfig": {
53
+ "access": "public"
54
+ },
55
+ "dependencies": {
56
+ "@ruvector/emergent-time": "^0.1.0"
57
+ },
58
+ "peerDependencies": {
59
+ "@ruvector/rvf": "^0.2.0"
60
+ },
61
+ "peerDependenciesMeta": {
62
+ "@ruvector/rvf": {
63
+ "optional": true
64
+ }
65
+ },
66
+ "optionalDependencies": {
67
+ "@metaharness/kernel-darwin-arm64": "0.1.0",
68
+ "@metaharness/kernel-darwin-x64": "0.1.0",
69
+ "@metaharness/kernel-linux-x64-gnu": "0.1.0",
70
+ "@metaharness/kernel-linux-arm64-gnu": "0.1.0",
71
+ "@metaharness/kernel-win32-x64-msvc": "0.1.0"
72
+ },
73
+ "engines": {
74
+ "node": ">=20.0.0"
75
+ }
76
+ }