@osmosis-ai/mesh-server 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.
@@ -0,0 +1,10 @@
1
+ export interface MeshServerConfig {
2
+ /** Port to listen on (default: 7433) */
3
+ port: number;
4
+ /** Path to SQLite database for mesh storage (default: ':memory:') */
5
+ dbPath: string;
6
+ /** Allow anonymous contributions (default: true) */
7
+ allowAnonymous: boolean;
8
+ }
9
+ export declare const DEFAULT_MESH_CONFIG: MeshServerConfig;
10
+ export declare function resolveMeshConfig(partial?: Partial<MeshServerConfig>): MeshServerConfig;
package/dist/config.js ADDED
@@ -0,0 +1,9 @@
1
+ export const DEFAULT_MESH_CONFIG = {
2
+ port: 7433,
3
+ dbPath: ':memory:',
4
+ allowAnonymous: true,
5
+ };
6
+ export function resolveMeshConfig(partial) {
7
+ return { ...DEFAULT_MESH_CONFIG, ...partial };
8
+ }
9
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AASA,MAAM,CAAC,MAAM,mBAAmB,GAAqB;IACnD,IAAI,EAAE,IAAI;IACV,MAAM,EAAE,UAAU;IAClB,cAAc,EAAE,IAAI;CACrB,CAAC;AAEF,MAAM,UAAU,iBAAiB,CAAC,OAAmC;IACnE,OAAO,EAAE,GAAG,mBAAmB,EAAE,GAAG,OAAO,EAAE,CAAC;AAChD,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Production entrypoint for the Osmosis mesh server.
3
+ * Reads config from environment variables and starts the server.
4
+ */
5
+ import { startMeshServer } from './index.js';
6
+ import { mkdirSync } from 'node:fs';
7
+ import { dirname } from 'node:path';
8
+ const port = parseInt(process.env.MESH_PORT || '7433', 10);
9
+ const dbPath = process.env.MESH_DB_PATH || '/data/mesh.db';
10
+ // Ensure data directory exists
11
+ try {
12
+ mkdirSync(dirname(dbPath), { recursive: true });
13
+ }
14
+ catch { }
15
+ // startMeshServer already calls server.listen() internally
16
+ const handle = startMeshServer({ port, dbPath, allowAnonymous: true });
17
+ console.log(`🧠 Osmosis mesh server running on port ${port}`);
18
+ console.log(` Database: ${dbPath}`);
19
+ console.log(` Ready to accept contributions`);
20
+ // Graceful shutdown
21
+ process.on('SIGTERM', () => {
22
+ console.log('Shutting down...');
23
+ handle.stop();
24
+ process.exit(0);
25
+ });
26
+ process.on('SIGINT', () => {
27
+ console.log('Shutting down...');
28
+ handle.stop();
29
+ process.exit(0);
30
+ });
31
+ //# sourceMappingURL=entrypoint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entrypoint.js","sourceRoot":"","sources":["../src/entrypoint.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC;AAC3D,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,eAAe,CAAC;AAE3D,+BAA+B;AAC/B,IAAI,CAAC;IACH,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAClD,CAAC;AAAC,MAAM,CAAC,CAAA,CAAC;AAEV,2DAA2D;AAC3D,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC;AAEvE,OAAO,CAAC,GAAG,CAAC,0CAA0C,IAAI,EAAE,CAAC,CAAC;AAC9D,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM,EAAE,CAAC,CAAC;AACtC,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;AAEhD,oBAAoB;AACpB,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;IACzB,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAChC,MAAM,CAAC,IAAI,EAAE,CAAC;IACd,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;IACxB,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAChC,MAAM,CAAC,IAAI,EAAE,CAAC;IACd,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { AtomStore } from '@osmosis-ai/core';
2
+ import { type MeshServerConfig } from './config.js';
3
+ import type { Server } from 'node:http';
4
+ export { createMeshServer } from './server.js';
5
+ export { resolveMeshConfig, DEFAULT_MESH_CONFIG } from './config.js';
6
+ export type { MeshServerConfig } from './config.js';
7
+ export interface MeshServerHandle {
8
+ store: AtomStore;
9
+ server: Server;
10
+ stop(): void;
11
+ }
12
+ export declare function startMeshServer(partial?: Partial<MeshServerConfig>): MeshServerHandle;
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ import { AtomStore } from '@osmosis-ai/core';
2
+ import { createMeshServer } from './server.js';
3
+ import { resolveMeshConfig } from './config.js';
4
+ export { createMeshServer } from './server.js';
5
+ export { resolveMeshConfig, DEFAULT_MESH_CONFIG } from './config.js';
6
+ export function startMeshServer(partial) {
7
+ const config = resolveMeshConfig(partial);
8
+ const store = new AtomStore(config.dbPath);
9
+ const server = createMeshServer(store, config);
10
+ return {
11
+ store,
12
+ server,
13
+ stop() {
14
+ server.close();
15
+ store.close();
16
+ },
17
+ };
18
+ }
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAyB,MAAM,aAAa,CAAC;AAGvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AASrE,MAAM,UAAU,eAAe,CAAC,OAAmC;IACjE,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAE/C,OAAO;QACL,KAAK;QACL,MAAM;QACN,IAAI;YACF,MAAM,CAAC,KAAK,EAAE,CAAC;YACf,KAAK,CAAC,KAAK,EAAE,CAAC;QAChB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { type Server } from 'node:http';
2
+ import { AtomStore } from '@osmosis-ai/core';
3
+ import type { MeshServerConfig } from './config.js';
4
+ /**
5
+ * Create the centralized mesh HTTP server.
6
+ *
7
+ * Routes:
8
+ * POST /mesh/contribute — submit atoms to the mesh
9
+ * GET /mesh/atoms?since=<ISO> — get atoms since timestamp
10
+ * GET /mesh/query?q=&type=&limit= — query mesh for relevant knowledge
11
+ * GET /mesh/stats — mesh statistics
12
+ */
13
+ export declare function createMeshServer(store: AtomStore, config: MeshServerConfig): Server;
package/dist/server.js ADDED
@@ -0,0 +1,116 @@
1
+ import { createServer as createHttpServer } from 'node:http';
2
+ function json(res, status, data) {
3
+ res.writeHead(status, { 'Content-Type': 'application/json' });
4
+ res.end(JSON.stringify(data));
5
+ }
6
+ function readBody(req) {
7
+ return new Promise((resolve, reject) => {
8
+ const chunks = [];
9
+ req.on('data', (c) => chunks.push(c));
10
+ req.on('end', () => resolve(Buffer.concat(chunks).toString()));
11
+ req.on('error', reject);
12
+ });
13
+ }
14
+ /**
15
+ * Create the centralized mesh HTTP server.
16
+ *
17
+ * Routes:
18
+ * POST /mesh/contribute — submit atoms to the mesh
19
+ * GET /mesh/atoms?since=<ISO> — get atoms since timestamp
20
+ * GET /mesh/query?q=&type=&limit= — query mesh for relevant knowledge
21
+ * GET /mesh/stats — mesh statistics
22
+ */
23
+ export function createMeshServer(store, config) {
24
+ const server = createHttpServer(async (req, res) => {
25
+ const url = new URL(req.url ?? '/', `http://localhost:${config.port}`);
26
+ const path = url.pathname;
27
+ const method = req.method ?? 'GET';
28
+ try {
29
+ // POST /mesh/contribute — accept atoms from clients
30
+ if (method === 'POST' && path === '/mesh/contribute') {
31
+ const body = JSON.parse(await readBody(req));
32
+ const atoms = Array.isArray(body) ? body : [body];
33
+ const results = [];
34
+ for (const atomData of atoms) {
35
+ // Strip client-side auto fields; mesh generates its own
36
+ const { id, created_at, updated_at, ...data } = atomData;
37
+ // Force quarantine trust tier on mesh
38
+ data.trust_tier = 'quarantine';
39
+ let result;
40
+ if (data.type === 'tool') {
41
+ result = store.createToolAtom(data);
42
+ }
43
+ else if (data.type === 'negative') {
44
+ result = store.createNegativeAtom(data);
45
+ }
46
+ else {
47
+ result = store.createAtom(data);
48
+ }
49
+ // Detect dedup: if evidence_count > 1, it was merged
50
+ const ec = result.evidence_count;
51
+ results.push({
52
+ id: result.id,
53
+ status: ec && ec > 1 ? 'deduped' : 'created',
54
+ });
55
+ }
56
+ return json(res, 200, { accepted: results.length, results });
57
+ }
58
+ // GET /mesh/atoms?since=<ISO>
59
+ if (method === 'GET' && path === '/mesh/atoms') {
60
+ const since = url.searchParams.get('since');
61
+ let atoms = store.getAll();
62
+ if (since) {
63
+ atoms = atoms.filter(a => a.updated_at > since);
64
+ }
65
+ return json(res, 200, atoms);
66
+ }
67
+ // GET /mesh/query?q=<search>&type=<type>&limit=<n>
68
+ if (method === 'GET' && path === '/mesh/query') {
69
+ const q = url.searchParams.get('q') ?? '';
70
+ const type = url.searchParams.get('type');
71
+ const limit = parseInt(url.searchParams.get('limit') ?? '20', 10);
72
+ let atoms;
73
+ if (q) {
74
+ atoms = store.search(q);
75
+ }
76
+ else if (type) {
77
+ atoms = store.queryByType(type);
78
+ }
79
+ else {
80
+ atoms = store.getAll();
81
+ }
82
+ if (type && q) {
83
+ atoms = atoms.filter(a => a.type === type);
84
+ }
85
+ atoms = atoms.slice(0, limit);
86
+ return json(res, 200, atoms);
87
+ }
88
+ // GET /mesh/stats
89
+ if (method === 'GET' && path === '/mesh/stats') {
90
+ const all = store.getAll();
91
+ const contributors = new Set(all.map(a => a.source_agent_hash));
92
+ const topAtoms = [...all]
93
+ .sort((a, b) => b.fitness_score - a.fitness_score)
94
+ .slice(0, 10);
95
+ return json(res, 200, {
96
+ totalAtoms: all.length,
97
+ contributors: contributors.size,
98
+ topAtoms: topAtoms.map(a => ({
99
+ id: a.id,
100
+ type: a.type,
101
+ observation: a.observation.slice(0, 120),
102
+ fitness_score: a.fitness_score,
103
+ })),
104
+ });
105
+ }
106
+ json(res, 404, { error: 'Not found' });
107
+ }
108
+ catch (err) {
109
+ const status = err.name === 'ZodError' ? 400 : 500;
110
+ json(res, status, { error: err.message ?? 'Internal error' });
111
+ }
112
+ });
113
+ server.listen(config.port);
114
+ return server;
115
+ }
116
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@osmosis-ai/mesh-server",
3
+ "version": "0.1.0",
4
+ "description": "Centralized mesh server for Osmosis knowledge sharing",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "scripts": {
9
+ "build": "tsc",
10
+ "test": "vitest run",
11
+ "test:watch": "vitest"
12
+ },
13
+ "dependencies": {
14
+ "@osmosis-ai/core": "*"
15
+ },
16
+ "devDependencies": {
17
+ "better-sqlite3": "^11.7.0",
18
+ "@types/better-sqlite3": "^7.6.12",
19
+ "typescript": "^5.7.0",
20
+ "vitest": "^3.0.0"
21
+ },
22
+ "license": "MIT"
23
+ }
@@ -0,0 +1,107 @@
1
+ import { describe, it, expect, afterEach } from 'vitest';
2
+ import { AtomStore } from '@osmosis-ai/core';
3
+ import { startMeshServer, type MeshServerHandle } from '../index.js';
4
+
5
+ const PORT = 19600;
6
+
7
+ function makeToolAtom(toolName: string, observation: string) {
8
+ return {
9
+ type: 'tool' as const,
10
+ observation,
11
+ context: `testing ${toolName}`,
12
+ confidence: 0.8,
13
+ fitness_score: 0.7,
14
+ trust_tier: 'local' as const,
15
+ source_agent_hash: 'test-agent-' + toolName,
16
+ decay_rate: 0.99,
17
+ tool_name: toolName,
18
+ params_hash: 'abc123',
19
+ outcome: 'success' as const,
20
+ error_signature: null,
21
+ latency_ms: 100,
22
+ reliability_score: 0.9,
23
+ };
24
+ }
25
+
26
+ describe('mesh server', () => {
27
+ let mesh: MeshServerHandle;
28
+
29
+ afterEach(() => {
30
+ try { mesh?.stop(); } catch {}
31
+ });
32
+
33
+ it('POST /mesh/contribute accepts atoms', async () => {
34
+ mesh = startMeshServer({ port: PORT, dbPath: ':memory:' });
35
+ const res = await fetch(`http://localhost:${PORT}/mesh/contribute`, {
36
+ method: 'POST',
37
+ headers: { 'Content-Type': 'application/json' },
38
+ body: JSON.stringify(makeToolAtom('test', 'test observation')),
39
+ });
40
+ expect(res.ok).toBe(true);
41
+ const body = await res.json() as any;
42
+ expect(body.accepted).toBe(1);
43
+ expect(mesh.store.getAll().length).toBe(1);
44
+ // Contributed atoms are quarantined
45
+ expect(mesh.store.getAll()[0]!.trust_tier).toBe('quarantine');
46
+ });
47
+
48
+ it('GET /mesh/atoms returns all atoms', async () => {
49
+ mesh = startMeshServer({ port: PORT, dbPath: ':memory:' });
50
+ mesh.store.createToolAtom(makeToolAtom('t1', 'obs one'));
51
+ mesh.store.createToolAtom(makeToolAtom('t2', 'obs two completely different'));
52
+
53
+ const res = await fetch(`http://localhost:${PORT}/mesh/atoms`);
54
+ const atoms = await res.json() as any[];
55
+ expect(atoms.length).toBe(2);
56
+ });
57
+
58
+ it('GET /mesh/atoms?since= filters by time', async () => {
59
+ mesh = startMeshServer({ port: PORT, dbPath: ':memory:' });
60
+ mesh.store.createToolAtom(makeToolAtom('old', 'old observation'));
61
+ const since = new Date().toISOString();
62
+ await new Promise(r => setTimeout(r, 50));
63
+ mesh.store.createToolAtom(makeToolAtom('new', 'completely new different observation'));
64
+
65
+ const res = await fetch(`http://localhost:${PORT}/mesh/atoms?since=${encodeURIComponent(since)}`);
66
+ const atoms = await res.json() as any[];
67
+ expect(atoms.length).toBe(1);
68
+ expect(atoms[0].tool_name).toBe('new');
69
+ });
70
+
71
+ it('GET /mesh/query searches atoms', async () => {
72
+ mesh = startMeshServer({ port: PORT, dbPath: ':memory:' });
73
+ mesh.store.createToolAtom(makeToolAtom('browser', 'browser click fails'));
74
+ mesh.store.createToolAtom(makeToolAtom('fetch', 'fetch times out'));
75
+
76
+ const res = await fetch(`http://localhost:${PORT}/mesh/query?q=browser`);
77
+ const atoms = await res.json() as any[];
78
+ expect(atoms.length).toBe(1);
79
+ });
80
+
81
+ it('GET /mesh/stats returns statistics', async () => {
82
+ mesh = startMeshServer({ port: PORT, dbPath: ':memory:' });
83
+ mesh.store.createToolAtom(makeToolAtom('t1', 'obs one'));
84
+ mesh.store.createToolAtom(makeToolAtom('t2', 'obs two completely different'));
85
+
86
+ const res = await fetch(`http://localhost:${PORT}/mesh/stats`);
87
+ const stats = await res.json() as any;
88
+ expect(stats.totalAtoms).toBe(2);
89
+ expect(stats.contributors).toBeGreaterThanOrEqual(1);
90
+ });
91
+
92
+ it('batch contribute accepts array', async () => {
93
+ mesh = startMeshServer({ port: PORT, dbPath: ':memory:' });
94
+ const atoms = [
95
+ makeToolAtom('t1', 'first observation'),
96
+ makeToolAtom('t2', 'second completely different observation'),
97
+ ];
98
+ const res = await fetch(`http://localhost:${PORT}/mesh/contribute`, {
99
+ method: 'POST',
100
+ headers: { 'Content-Type': 'application/json' },
101
+ body: JSON.stringify(atoms),
102
+ });
103
+ const body = await res.json() as any;
104
+ expect(body.accepted).toBe(2);
105
+ expect(mesh.store.getAll().length).toBe(2);
106
+ });
107
+ });
package/src/config.ts ADDED
@@ -0,0 +1,18 @@
1
+ export interface MeshServerConfig {
2
+ /** Port to listen on (default: 7433) */
3
+ port: number;
4
+ /** Path to SQLite database for mesh storage (default: ':memory:') */
5
+ dbPath: string;
6
+ /** Allow anonymous contributions (default: true) */
7
+ allowAnonymous: boolean;
8
+ }
9
+
10
+ export const DEFAULT_MESH_CONFIG: MeshServerConfig = {
11
+ port: 7433,
12
+ dbPath: ':memory:',
13
+ allowAnonymous: true,
14
+ };
15
+
16
+ export function resolveMeshConfig(partial?: Partial<MeshServerConfig>): MeshServerConfig {
17
+ return { ...DEFAULT_MESH_CONFIG, ...partial };
18
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Production entrypoint for the Osmosis mesh server.
3
+ * Reads config from environment variables and starts the server.
4
+ */
5
+ import { startMeshServer } from './index.js';
6
+ import { mkdirSync } from 'node:fs';
7
+ import { dirname } from 'node:path';
8
+
9
+ const port = parseInt(process.env.MESH_PORT || '7433', 10);
10
+ const dbPath = process.env.MESH_DB_PATH || '/data/mesh.db';
11
+
12
+ // Ensure data directory exists
13
+ try {
14
+ mkdirSync(dirname(dbPath), { recursive: true });
15
+ } catch {}
16
+
17
+ // startMeshServer already calls server.listen() internally
18
+ const handle = startMeshServer({ port, dbPath, allowAnonymous: true });
19
+
20
+ console.log(`🧠 Osmosis mesh server running on port ${port}`);
21
+ console.log(` Database: ${dbPath}`);
22
+ console.log(` Ready to accept contributions`);
23
+
24
+ // Graceful shutdown
25
+ process.on('SIGTERM', () => {
26
+ console.log('Shutting down...');
27
+ handle.stop();
28
+ process.exit(0);
29
+ });
30
+
31
+ process.on('SIGINT', () => {
32
+ console.log('Shutting down...');
33
+ handle.stop();
34
+ process.exit(0);
35
+ });
package/src/index.ts ADDED
@@ -0,0 +1,29 @@
1
+ import { AtomStore } from '@osmosis-ai/core';
2
+ import { createMeshServer } from './server.js';
3
+ import { resolveMeshConfig, type MeshServerConfig } from './config.js';
4
+ import type { Server } from 'node:http';
5
+
6
+ export { createMeshServer } from './server.js';
7
+ export { resolveMeshConfig, DEFAULT_MESH_CONFIG } from './config.js';
8
+ export type { MeshServerConfig } from './config.js';
9
+
10
+ export interface MeshServerHandle {
11
+ store: AtomStore;
12
+ server: Server;
13
+ stop(): void;
14
+ }
15
+
16
+ export function startMeshServer(partial?: Partial<MeshServerConfig>): MeshServerHandle {
17
+ const config = resolveMeshConfig(partial);
18
+ const store = new AtomStore(config.dbPath);
19
+ const server = createMeshServer(store, config);
20
+
21
+ return {
22
+ store,
23
+ server,
24
+ stop() {
25
+ server.close();
26
+ store.close();
27
+ },
28
+ };
29
+ }
package/src/server.ts ADDED
@@ -0,0 +1,130 @@
1
+ import { createServer as createHttpServer, type IncomingMessage, type ServerResponse, type Server } from 'node:http';
2
+ import { AtomStore } from '@osmosis-ai/core';
3
+ import type { KnowledgeAtom } from '@osmosis-ai/core';
4
+ import type { MeshServerConfig } from './config.js';
5
+
6
+ function json(res: ServerResponse, status: number, data: unknown): void {
7
+ res.writeHead(status, { 'Content-Type': 'application/json' });
8
+ res.end(JSON.stringify(data));
9
+ }
10
+
11
+ function readBody(req: IncomingMessage): Promise<string> {
12
+ return new Promise((resolve, reject) => {
13
+ const chunks: Buffer[] = [];
14
+ req.on('data', (c: Buffer) => chunks.push(c));
15
+ req.on('end', () => resolve(Buffer.concat(chunks).toString()));
16
+ req.on('error', reject);
17
+ });
18
+ }
19
+
20
+ /**
21
+ * Create the centralized mesh HTTP server.
22
+ *
23
+ * Routes:
24
+ * POST /mesh/contribute — submit atoms to the mesh
25
+ * GET /mesh/atoms?since=<ISO> — get atoms since timestamp
26
+ * GET /mesh/query?q=&type=&limit= — query mesh for relevant knowledge
27
+ * GET /mesh/stats — mesh statistics
28
+ */
29
+ export function createMeshServer(store: AtomStore, config: MeshServerConfig): Server {
30
+ const server = createHttpServer(async (req: IncomingMessage, res: ServerResponse) => {
31
+ const url = new URL(req.url ?? '/', `http://localhost:${config.port}`);
32
+ const path = url.pathname;
33
+ const method = req.method ?? 'GET';
34
+
35
+ try {
36
+ // POST /mesh/contribute — accept atoms from clients
37
+ if (method === 'POST' && path === '/mesh/contribute') {
38
+ const body = JSON.parse(await readBody(req));
39
+ const atoms: any[] = Array.isArray(body) ? body : [body];
40
+ const results: Array<{ id: string; status: 'created' | 'deduped' }> = [];
41
+
42
+ for (const atomData of atoms) {
43
+ // Strip client-side auto fields; mesh generates its own
44
+ const { id, created_at, updated_at, ...data } = atomData;
45
+ // Force quarantine trust tier on mesh
46
+ data.trust_tier = 'quarantine';
47
+
48
+ let result: KnowledgeAtom;
49
+ if (data.type === 'tool') {
50
+ result = store.createToolAtom(data);
51
+ } else if (data.type === 'negative') {
52
+ result = store.createNegativeAtom(data);
53
+ } else {
54
+ result = store.createAtom(data);
55
+ }
56
+
57
+ // Detect dedup: if evidence_count > 1, it was merged
58
+ const ec = (result as any).evidence_count;
59
+ results.push({
60
+ id: result.id,
61
+ status: ec && ec > 1 ? 'deduped' : 'created',
62
+ });
63
+ }
64
+
65
+ return json(res, 200, { accepted: results.length, results });
66
+ }
67
+
68
+ // GET /mesh/atoms?since=<ISO>
69
+ if (method === 'GET' && path === '/mesh/atoms') {
70
+ const since = url.searchParams.get('since');
71
+ let atoms = store.getAll();
72
+ if (since) {
73
+ atoms = atoms.filter(a => a.updated_at > since);
74
+ }
75
+ return json(res, 200, atoms);
76
+ }
77
+
78
+ // GET /mesh/query?q=<search>&type=<type>&limit=<n>
79
+ if (method === 'GET' && path === '/mesh/query') {
80
+ const q = url.searchParams.get('q') ?? '';
81
+ const type = url.searchParams.get('type');
82
+ const limit = parseInt(url.searchParams.get('limit') ?? '20', 10);
83
+
84
+ let atoms: KnowledgeAtom[];
85
+ if (q) {
86
+ atoms = store.search(q);
87
+ } else if (type) {
88
+ atoms = store.queryByType(type as any);
89
+ } else {
90
+ atoms = store.getAll();
91
+ }
92
+
93
+ if (type && q) {
94
+ atoms = atoms.filter(a => a.type === type);
95
+ }
96
+
97
+ atoms = atoms.slice(0, limit);
98
+ return json(res, 200, atoms);
99
+ }
100
+
101
+ // GET /mesh/stats
102
+ if (method === 'GET' && path === '/mesh/stats') {
103
+ const all = store.getAll();
104
+ const contributors = new Set(all.map(a => a.source_agent_hash));
105
+ const topAtoms = [...all]
106
+ .sort((a, b) => b.fitness_score - a.fitness_score)
107
+ .slice(0, 10);
108
+
109
+ return json(res, 200, {
110
+ totalAtoms: all.length,
111
+ contributors: contributors.size,
112
+ topAtoms: topAtoms.map(a => ({
113
+ id: a.id,
114
+ type: a.type,
115
+ observation: a.observation.slice(0, 120),
116
+ fitness_score: a.fitness_score,
117
+ })),
118
+ });
119
+ }
120
+
121
+ json(res, 404, { error: 'Not found' });
122
+ } catch (err: any) {
123
+ const status = err.name === 'ZodError' ? 400 : 500;
124
+ json(res, status, { error: err.message ?? 'Internal error' });
125
+ }
126
+ });
127
+
128
+ server.listen(config.port);
129
+ return server;
130
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ES2022",
5
+ "moduleResolution": "bundler",
6
+ "lib": ["ES2022"],
7
+ "outDir": "dist",
8
+ "rootDir": "src",
9
+ "declaration": true,
10
+ "strict": true,
11
+ "esModuleInterop": true,
12
+ "skipLibCheck": true,
13
+ "forceConsistentCasingInFileNames": true,
14
+ "resolveJsonModule": true,
15
+ "sourceMap": true,
16
+ "composite": true
17
+ },
18
+ "include": ["src"],
19
+ "exclude": ["node_modules", "dist", "**/*.test.ts"],
20
+ "references": [
21
+ { "path": "../core" }
22
+ ]
23
+ }