@zooid/context-mcp 0.9.1 → 0.11.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/dist/bin.js +94 -2
- package/dist/bin.js.map +1 -1
- package/dist/chunk-ZY2GPHFX.js +21208 -0
- package/dist/chunk-ZY2GPHFX.js.map +1 -0
- package/dist/index.js +24 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/factory.test.ts +63 -1
- package/src/factory.ts +43 -0
- package/src/index.ts +7 -1
- package/dist/chunk-QQD76TLH.js +0 -203
- package/dist/chunk-QQD76TLH.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
buildContextMcpServer,
|
|
3
3
|
callDaemon,
|
|
4
4
|
startDaemonSocketServer
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-ZY2GPHFX.js";
|
|
6
6
|
|
|
7
7
|
// src/spawn-registry.ts
|
|
8
8
|
import { randomUUID } from "crypto";
|
|
@@ -23,6 +23,7 @@ var SpawnRegistry = class {
|
|
|
23
23
|
|
|
24
24
|
// src/factory.ts
|
|
25
25
|
import { createRequire } from "module";
|
|
26
|
+
import { dirname } from "path";
|
|
26
27
|
function resolveDefaultBin() {
|
|
27
28
|
const req = createRequire(import.meta.url);
|
|
28
29
|
return req.resolve("@zooid/context-mcp/bin");
|
|
@@ -32,7 +33,25 @@ function getDefaultBin() {
|
|
|
32
33
|
if (!cachedDefaultBin) cachedDefaultBin = resolveDefaultBin();
|
|
33
34
|
return cachedDefaultBin;
|
|
34
35
|
}
|
|
36
|
+
var CONTEXT_CONTAINER_BIN_DIR = "/zooid/context-mcp";
|
|
37
|
+
var CONTEXT_CONTAINER_BIN = `${CONTEXT_CONTAINER_BIN_DIR}/bin.js`;
|
|
38
|
+
var CONTEXT_CONTAINER_SOCK = "/zooid/context.sock";
|
|
39
|
+
function contextContainerMounts(opts) {
|
|
40
|
+
const binFile = opts.binPath ?? getDefaultBin();
|
|
41
|
+
return [
|
|
42
|
+
{ path: dirname(binFile), target: CONTEXT_CONTAINER_BIN_DIR, mode: "ro" },
|
|
43
|
+
{ path: opts.sockPath, target: CONTEXT_CONTAINER_SOCK, mode: "rw" }
|
|
44
|
+
];
|
|
45
|
+
}
|
|
35
46
|
function buildContextServerSpec(opts) {
|
|
47
|
+
if (opts.containerize) {
|
|
48
|
+
return {
|
|
49
|
+
name: "zooid-context",
|
|
50
|
+
command: "node",
|
|
51
|
+
args: [CONTEXT_CONTAINER_BIN, "--spawn-id", opts.spawnId],
|
|
52
|
+
env: [{ name: "ZOOID_DAEMON_SOCK", value: CONTEXT_CONTAINER_SOCK }]
|
|
53
|
+
};
|
|
54
|
+
}
|
|
36
55
|
return {
|
|
37
56
|
name: "zooid-context",
|
|
38
57
|
command: process.execPath,
|
|
@@ -41,10 +60,14 @@ function buildContextServerSpec(opts) {
|
|
|
41
60
|
};
|
|
42
61
|
}
|
|
43
62
|
export {
|
|
63
|
+
CONTEXT_CONTAINER_BIN,
|
|
64
|
+
CONTEXT_CONTAINER_BIN_DIR,
|
|
65
|
+
CONTEXT_CONTAINER_SOCK,
|
|
44
66
|
SpawnRegistry,
|
|
45
67
|
buildContextMcpServer,
|
|
46
68
|
buildContextServerSpec,
|
|
47
69
|
callDaemon,
|
|
70
|
+
contextContainerMounts,
|
|
48
71
|
startDaemonSocketServer
|
|
49
72
|
};
|
|
50
73
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/spawn-registry.ts","../src/factory.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto'\nimport type { SpawnBinding } from './types.js'\nimport type { TransportContextProvider, ThreadRef } from '@zooid/core'\n\nexport class SpawnRegistry {\n private readonly bindings = new Map<string, SpawnBinding>()\n\n register(input: {\n agentName: string\n threadRef: ThreadRef\n provider: TransportContextProvider\n }): string {\n const spawnId = randomUUID()\n this.bindings.set(spawnId, { spawnId, ...input })\n return spawnId\n }\n\n get(spawnId: string): SpawnBinding | undefined {\n return this.bindings.get(spawnId)\n }\n\n release(spawnId: string): void {\n this.bindings.delete(spawnId)\n }\n}\n","import { createRequire } from 'node:module'\nimport type { ZooidContextServerSpec } from './types.js'\n\n/**\n * Resolve `dist/bin.js` via Node's runtime module resolver rather than\n * `import.meta.url`. tsup bundles this file into the CLI's own chunk, so\n * `import.meta.url` at runtime points to the CLI bundle — not this\n * package's dist. `createRequire` walks the runtime `node_modules` tree\n * instead and finds the package wherever it actually lives.\n */\nfunction resolveDefaultBin(): string {\n const req = createRequire(import.meta.url)\n // Resolve via the dedicated `./bin` export → `./dist/bin.js`. Avoids the\n // exports-restriction surprise of importing `./package.json`.\n return req.resolve('@zooid/context-mcp/bin')\n}\n\nlet cachedDefaultBin: string | null = null\nfunction getDefaultBin(): string {\n if (!cachedDefaultBin) cachedDefaultBin = resolveDefaultBin()\n return cachedDefaultBin\n}\n\nexport function buildContextServerSpec(opts: {\n spawnId: string\n sockPath: string\n binPath?: string\n}): ZooidContextServerSpec {\n return {\n name: 'zooid-context',\n command: process.execPath,\n args: [opts.binPath ?? getDefaultBin(), '--spawn-id', opts.spawnId],\n env: [{ name: 'ZOOID_DAEMON_SOCK', value: opts.sockPath }],\n }\n}\n"],"mappings":";;;;;;;AAAA,SAAS,kBAAkB;AAIpB,IAAM,gBAAN,MAAoB;AAAA,EACR,WAAW,oBAAI,IAA0B;AAAA,EAE1D,SAAS,OAIE;AACT,UAAM,UAAU,WAAW;AAC3B,SAAK,SAAS,IAAI,SAAS,EAAE,SAAS,GAAG,MAAM,CAAC;AAChD,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,SAA2C;AAC7C,WAAO,KAAK,SAAS,IAAI,OAAO;AAAA,EAClC;AAAA,EAEA,QAAQ,SAAuB;AAC7B,SAAK,SAAS,OAAO,OAAO;AAAA,EAC9B;AACF;;;ACxBA,SAAS,qBAAqB;
|
|
1
|
+
{"version":3,"sources":["../src/spawn-registry.ts","../src/factory.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto'\nimport type { SpawnBinding } from './types.js'\nimport type { TransportContextProvider, ThreadRef } from '@zooid/core'\n\nexport class SpawnRegistry {\n private readonly bindings = new Map<string, SpawnBinding>()\n\n register(input: {\n agentName: string\n threadRef: ThreadRef\n provider: TransportContextProvider\n }): string {\n const spawnId = randomUUID()\n this.bindings.set(spawnId, { spawnId, ...input })\n return spawnId\n }\n\n get(spawnId: string): SpawnBinding | undefined {\n return this.bindings.get(spawnId)\n }\n\n release(spawnId: string): void {\n this.bindings.delete(spawnId)\n }\n}\n","import { createRequire } from 'node:module'\nimport { dirname } from 'node:path'\nimport type { AcpMount } from '@zooid/core'\nimport type { ZooidContextServerSpec } from './types.js'\n\n/**\n * Resolve `dist/bin.js` via Node's runtime module resolver rather than\n * `import.meta.url`. tsup bundles this file into the CLI's own chunk, so\n * `import.meta.url` at runtime points to the CLI bundle — not this\n * package's dist. `createRequire` walks the runtime `node_modules` tree\n * instead and finds the package wherever it actually lives.\n */\nfunction resolveDefaultBin(): string {\n const req = createRequire(import.meta.url)\n // Resolve via the dedicated `./bin` export → `./dist/bin.js`. Avoids the\n // exports-restriction surprise of importing `./package.json`.\n return req.resolve('@zooid/context-mcp/bin')\n}\n\nlet cachedDefaultBin: string | null = null\nfunction getDefaultBin(): string {\n if (!cachedDefaultBin) cachedDefaultBin = resolveDefaultBin()\n return cachedDefaultBin\n}\n\n/**\n * Fixed container-side paths for the containerized MCP spec. The daemon\n * bind-mounts the host `dist/` here (ro) and the daemon socket here (rw) so\n * opencode can spawn the zooid-context MCP subprocess inside its own container.\n */\nexport const CONTEXT_CONTAINER_BIN_DIR = '/zooid/context-mcp'\nexport const CONTEXT_CONTAINER_BIN = `${CONTEXT_CONTAINER_BIN_DIR}/bin.js`\nexport const CONTEXT_CONTAINER_SOCK = '/zooid/context.sock'\n\n/**\n * The two bind-mounts a containerized, context-enabled agent needs. The bin dir\n * is read-only (self-contained bundle); the socket is read-write (the MCP\n * subprocess connect()s to it). Host sources default to the resolved package\n * dist and the passed daemon socket path.\n */\nexport function contextContainerMounts(opts: {\n sockPath: string\n binPath?: string\n}): AcpMount[] {\n const binFile = opts.binPath ?? getDefaultBin()\n return [\n { path: dirname(binFile), target: CONTEXT_CONTAINER_BIN_DIR, mode: 'ro' },\n { path: opts.sockPath, target: CONTEXT_CONTAINER_SOCK, mode: 'rw' },\n ]\n}\n\nexport function buildContextServerSpec(opts: {\n spawnId: string\n sockPath: string\n binPath?: string\n /**\n * When set, emit a spec that resolves INSIDE the agent container: bare `node`\n * (image PATH), the bind-mounted bin path, and the bind-mounted socket path.\n * The host `sockPath`/`binPath` still feed `contextContainerMounts`, but do\n * not appear in the emitted command. Absent → host-runtime spec (unchanged).\n */\n containerize?: boolean\n}): ZooidContextServerSpec {\n if (opts.containerize) {\n return {\n name: 'zooid-context',\n command: 'node',\n args: [CONTEXT_CONTAINER_BIN, '--spawn-id', opts.spawnId],\n env: [{ name: 'ZOOID_DAEMON_SOCK', value: CONTEXT_CONTAINER_SOCK }],\n }\n }\n return {\n name: 'zooid-context',\n command: process.execPath,\n args: [opts.binPath ?? getDefaultBin(), '--spawn-id', opts.spawnId],\n env: [{ name: 'ZOOID_DAEMON_SOCK', value: opts.sockPath }],\n }\n}\n"],"mappings":";;;;;;;AAAA,SAAS,kBAAkB;AAIpB,IAAM,gBAAN,MAAoB;AAAA,EACR,WAAW,oBAAI,IAA0B;AAAA,EAE1D,SAAS,OAIE;AACT,UAAM,UAAU,WAAW;AAC3B,SAAK,SAAS,IAAI,SAAS,EAAE,SAAS,GAAG,MAAM,CAAC;AAChD,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,SAA2C;AAC7C,WAAO,KAAK,SAAS,IAAI,OAAO;AAAA,EAClC;AAAA,EAEA,QAAQ,SAAuB;AAC7B,SAAK,SAAS,OAAO,OAAO;AAAA,EAC9B;AACF;;;ACxBA,SAAS,qBAAqB;AAC9B,SAAS,eAAe;AAWxB,SAAS,oBAA4B;AACnC,QAAM,MAAM,cAAc,YAAY,GAAG;AAGzC,SAAO,IAAI,QAAQ,wBAAwB;AAC7C;AAEA,IAAI,mBAAkC;AACtC,SAAS,gBAAwB;AAC/B,MAAI,CAAC,iBAAkB,oBAAmB,kBAAkB;AAC5D,SAAO;AACT;AAOO,IAAM,4BAA4B;AAClC,IAAM,wBAAwB,GAAG,yBAAyB;AAC1D,IAAM,yBAAyB;AAQ/B,SAAS,uBAAuB,MAGxB;AACb,QAAM,UAAU,KAAK,WAAW,cAAc;AAC9C,SAAO;AAAA,IACL,EAAE,MAAM,QAAQ,OAAO,GAAG,QAAQ,2BAA2B,MAAM,KAAK;AAAA,IACxE,EAAE,MAAM,KAAK,UAAU,QAAQ,wBAAwB,MAAM,KAAK;AAAA,EACpE;AACF;AAEO,SAAS,uBAAuB,MAWZ;AACzB,MAAI,KAAK,cAAc;AACrB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS;AAAA,MACT,MAAM,CAAC,uBAAuB,cAAc,KAAK,OAAO;AAAA,MACxD,KAAK,CAAC,EAAE,MAAM,qBAAqB,OAAO,uBAAuB,CAAC;AAAA,IACpE;AAAA,EACF;AACA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS,QAAQ;AAAA,IACjB,MAAM,CAAC,KAAK,WAAW,cAAc,GAAG,cAAc,KAAK,OAAO;AAAA,IAClE,KAAK,CAAC,EAAE,MAAM,qBAAqB,OAAO,KAAK,SAAS,CAAC;AAAA,EAC3D;AACF;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zooid/context-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Daemon-side stdio MCP server + per-spawn registry that exposes zooid_get_history / zooid_get_members / zooid_get_channel_info to ACP shims, backed by each transport's TransportContextProvider.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
33
33
|
"zod": "^3.23.0",
|
|
34
|
-
"@zooid/core": "^0.
|
|
34
|
+
"@zooid/core": "^0.11.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/node": "^22.0.0",
|
package/src/factory.test.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest'
|
|
2
2
|
import { existsSync } from 'node:fs'
|
|
3
|
-
import {
|
|
3
|
+
import { dirname } from 'node:path'
|
|
4
|
+
import {
|
|
5
|
+
buildContextServerSpec,
|
|
6
|
+
contextContainerMounts,
|
|
7
|
+
CONTEXT_CONTAINER_BIN,
|
|
8
|
+
CONTEXT_CONTAINER_BIN_DIR,
|
|
9
|
+
CONTEXT_CONTAINER_SOCK,
|
|
10
|
+
} from './factory.js'
|
|
4
11
|
|
|
5
12
|
describe('buildContextServerSpec', () => {
|
|
6
13
|
it('produces the ACP mcpServers entry the daemon passes to session/new', () => {
|
|
@@ -30,3 +37,58 @@ describe('buildContextServerSpec', () => {
|
|
|
30
37
|
expect(existsSync(spec.args[0])).toBe(true)
|
|
31
38
|
})
|
|
32
39
|
})
|
|
40
|
+
|
|
41
|
+
describe('buildContextServerSpec — containerize', () => {
|
|
42
|
+
it('emits an in-container command/paths when containerize is set', () => {
|
|
43
|
+
const spec = buildContextServerSpec({
|
|
44
|
+
spawnId: 'sid-1',
|
|
45
|
+
// host paths are irrelevant to the emitted command in container mode;
|
|
46
|
+
// they only feed the bind-mounts (see contextContainerMounts).
|
|
47
|
+
sockPath: '/home/ubuntu/hq/data/run/context.sock',
|
|
48
|
+
binPath: '/usr/lib/node_modules/zooid/node_modules/@zooid/context-mcp/dist/bin.js',
|
|
49
|
+
containerize: true,
|
|
50
|
+
})
|
|
51
|
+
expect(spec.name).toBe('zooid-context')
|
|
52
|
+
// bare `node`, resolved via the agent image PATH — NOT the host execPath.
|
|
53
|
+
expect(spec.command).toBe('node')
|
|
54
|
+
expect(spec.args[0]).toBe(CONTEXT_CONTAINER_BIN) // '/zooid/context-mcp/bin.js'
|
|
55
|
+
expect(spec.args).toContain('--spawn-id')
|
|
56
|
+
expect(spec.args).toContain('sid-1')
|
|
57
|
+
// env points at the container-side socket target, not the host path.
|
|
58
|
+
expect(spec.env).toEqual([{ name: 'ZOOID_DAEMON_SOCK', value: CONTEXT_CONTAINER_SOCK }])
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('leaves the host-runtime spec unchanged when containerize is absent', () => {
|
|
62
|
+
const spec = buildContextServerSpec({
|
|
63
|
+
spawnId: 'sid-2',
|
|
64
|
+
sockPath: '/run/zooid/daemon.sock',
|
|
65
|
+
binPath: '/host/bin.js',
|
|
66
|
+
})
|
|
67
|
+
expect(spec.command).toBe(process.execPath)
|
|
68
|
+
expect(spec.args[0]).toBe('/host/bin.js')
|
|
69
|
+
expect(spec.env).toEqual([{ name: 'ZOOID_DAEMON_SOCK', value: '/run/zooid/daemon.sock' }])
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
describe('contextContainerMounts', () => {
|
|
74
|
+
it('returns the bin dir (ro) and the socket (rw) with container targets', () => {
|
|
75
|
+
const mounts = contextContainerMounts({
|
|
76
|
+
sockPath: '/home/ubuntu/hq/data/run/context.sock',
|
|
77
|
+
binPath: '/opt/zooid/context-mcp/dist/bin.js',
|
|
78
|
+
})
|
|
79
|
+
expect(mounts).toEqual([
|
|
80
|
+
{ path: '/opt/zooid/context-mcp/dist', target: CONTEXT_CONTAINER_BIN_DIR, mode: 'ro' },
|
|
81
|
+
{ path: '/home/ubuntu/hq/data/run/context.sock', target: CONTEXT_CONTAINER_SOCK, mode: 'rw' },
|
|
82
|
+
])
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('defaults the bin dir to the resolved package dist on disk', () => {
|
|
86
|
+
const mounts = contextContainerMounts({ sockPath: '/tmp/x.sock' })
|
|
87
|
+
const binMount = mounts.find((m) => m.target === CONTEXT_CONTAINER_BIN_DIR)!
|
|
88
|
+
expect(binMount.path).toMatch(/context-mcp[/\\]dist$/)
|
|
89
|
+
expect(existsSync(binMount.path)).toBe(true)
|
|
90
|
+
// the mounted dir must actually contain the bin we reference in-container.
|
|
91
|
+
expect(existsSync(`${binMount.path}/bin.js`)).toBe(true)
|
|
92
|
+
expect(dirname(`${binMount.path}/bin.js`)).toBe(binMount.path)
|
|
93
|
+
})
|
|
94
|
+
})
|
package/src/factory.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { createRequire } from 'node:module'
|
|
2
|
+
import { dirname } from 'node:path'
|
|
3
|
+
import type { AcpMount } from '@zooid/core'
|
|
2
4
|
import type { ZooidContextServerSpec } from './types.js'
|
|
3
5
|
|
|
4
6
|
/**
|
|
@@ -21,11 +23,52 @@ function getDefaultBin(): string {
|
|
|
21
23
|
return cachedDefaultBin
|
|
22
24
|
}
|
|
23
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Fixed container-side paths for the containerized MCP spec. The daemon
|
|
28
|
+
* bind-mounts the host `dist/` here (ro) and the daemon socket here (rw) so
|
|
29
|
+
* opencode can spawn the zooid-context MCP subprocess inside its own container.
|
|
30
|
+
*/
|
|
31
|
+
export const CONTEXT_CONTAINER_BIN_DIR = '/zooid/context-mcp'
|
|
32
|
+
export const CONTEXT_CONTAINER_BIN = `${CONTEXT_CONTAINER_BIN_DIR}/bin.js`
|
|
33
|
+
export const CONTEXT_CONTAINER_SOCK = '/zooid/context.sock'
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The two bind-mounts a containerized, context-enabled agent needs. The bin dir
|
|
37
|
+
* is read-only (self-contained bundle); the socket is read-write (the MCP
|
|
38
|
+
* subprocess connect()s to it). Host sources default to the resolved package
|
|
39
|
+
* dist and the passed daemon socket path.
|
|
40
|
+
*/
|
|
41
|
+
export function contextContainerMounts(opts: {
|
|
42
|
+
sockPath: string
|
|
43
|
+
binPath?: string
|
|
44
|
+
}): AcpMount[] {
|
|
45
|
+
const binFile = opts.binPath ?? getDefaultBin()
|
|
46
|
+
return [
|
|
47
|
+
{ path: dirname(binFile), target: CONTEXT_CONTAINER_BIN_DIR, mode: 'ro' },
|
|
48
|
+
{ path: opts.sockPath, target: CONTEXT_CONTAINER_SOCK, mode: 'rw' },
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
|
|
24
52
|
export function buildContextServerSpec(opts: {
|
|
25
53
|
spawnId: string
|
|
26
54
|
sockPath: string
|
|
27
55
|
binPath?: string
|
|
56
|
+
/**
|
|
57
|
+
* When set, emit a spec that resolves INSIDE the agent container: bare `node`
|
|
58
|
+
* (image PATH), the bind-mounted bin path, and the bind-mounted socket path.
|
|
59
|
+
* The host `sockPath`/`binPath` still feed `contextContainerMounts`, but do
|
|
60
|
+
* not appear in the emitted command. Absent → host-runtime spec (unchanged).
|
|
61
|
+
*/
|
|
62
|
+
containerize?: boolean
|
|
28
63
|
}): ZooidContextServerSpec {
|
|
64
|
+
if (opts.containerize) {
|
|
65
|
+
return {
|
|
66
|
+
name: 'zooid-context',
|
|
67
|
+
command: 'node',
|
|
68
|
+
args: [CONTEXT_CONTAINER_BIN, '--spawn-id', opts.spawnId],
|
|
69
|
+
env: [{ name: 'ZOOID_DAEMON_SOCK', value: CONTEXT_CONTAINER_SOCK }],
|
|
70
|
+
}
|
|
71
|
+
}
|
|
29
72
|
return {
|
|
30
73
|
name: 'zooid-context',
|
|
31
74
|
command: process.execPath,
|
package/src/index.ts
CHANGED
|
@@ -2,5 +2,11 @@ export { SpawnRegistry } from './spawn-registry.js'
|
|
|
2
2
|
export { startDaemonSocketServer, callDaemon } from './daemon-socket.js'
|
|
3
3
|
export type { DaemonSocketHandle } from './daemon-socket.js'
|
|
4
4
|
export { buildContextMcpServer } from './mcp-server.js'
|
|
5
|
-
export {
|
|
5
|
+
export {
|
|
6
|
+
buildContextServerSpec,
|
|
7
|
+
contextContainerMounts,
|
|
8
|
+
CONTEXT_CONTAINER_BIN,
|
|
9
|
+
CONTEXT_CONTAINER_BIN_DIR,
|
|
10
|
+
CONTEXT_CONTAINER_SOCK,
|
|
11
|
+
} from './factory.js'
|
|
6
12
|
export type { SpawnBinding, ZooidContextServerSpec } from './types.js'
|
package/dist/chunk-QQD76TLH.js
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
// src/mcp-server.ts
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
-
var MAX_LIMIT = 200;
|
|
5
|
-
var DEFAULT_LIMIT = 50;
|
|
6
|
-
function buildContextMcpServer(opts) {
|
|
7
|
-
const server = new McpServer({ name: "zooid-context", version: "0.0.1" });
|
|
8
|
-
server.tool(
|
|
9
|
-
"zooid_get_history",
|
|
10
|
-
"Read every message in the current room chronologically \u2014 top-level messages and all thread replies. Each message has an optional `thread_id` so the agent can group by thread. For a scan-the-room overview without reply noise, use `zooid_get_recent_threads` instead. Supports `limit` + `before` pagination.",
|
|
11
|
-
{
|
|
12
|
-
limit: z.number().int().positive().optional(),
|
|
13
|
-
before: z.string().optional()
|
|
14
|
-
},
|
|
15
|
-
async ({ limit, before }) => {
|
|
16
|
-
const provider = await opts.resolve();
|
|
17
|
-
const clamped = Math.min(limit ?? DEFAULT_LIMIT, MAX_LIMIT);
|
|
18
|
-
const page = await provider.getRoomHistory("", { limit: clamped, before });
|
|
19
|
-
return { content: [{ type: "text", text: JSON.stringify(page) }] };
|
|
20
|
-
}
|
|
21
|
-
);
|
|
22
|
-
server.tool(
|
|
23
|
-
"zooid_get_recent_threads",
|
|
24
|
-
"Scan-the-room overview: top-level messages and thread roots in the current room, newest first. Each entry has `reply_count` and `last_activity_at` so the agent can spot active conversations. Drill into a thread with `zooid_get_thread_history(thread_id)` where `thread_id` is the entry's `id`.",
|
|
25
|
-
{
|
|
26
|
-
limit: z.number().int().positive().optional(),
|
|
27
|
-
before: z.string().optional()
|
|
28
|
-
},
|
|
29
|
-
async ({ limit, before }) => {
|
|
30
|
-
const provider = await opts.resolve();
|
|
31
|
-
const clamped = Math.min(limit ?? DEFAULT_LIMIT, MAX_LIMIT);
|
|
32
|
-
const page = await provider.getRecentThreads("", { limit: clamped, before });
|
|
33
|
-
return { content: [{ type: "text", text: JSON.stringify(page) }] };
|
|
34
|
-
}
|
|
35
|
-
);
|
|
36
|
-
server.tool(
|
|
37
|
-
"zooid_get_thread_history",
|
|
38
|
-
"Drill into a specific thread: the root message followed by all replies in chronological order. Pass the `thread_id` from a `zooid_get_recent_threads` entry or a `Message.thread_id` from `zooid_get_history`.",
|
|
39
|
-
{
|
|
40
|
-
thread_id: z.string(),
|
|
41
|
-
limit: z.number().int().positive().optional(),
|
|
42
|
-
before: z.string().optional()
|
|
43
|
-
},
|
|
44
|
-
async ({ thread_id, limit, before }) => {
|
|
45
|
-
const provider = await opts.resolve();
|
|
46
|
-
const clamped = Math.min(limit ?? DEFAULT_LIMIT, MAX_LIMIT);
|
|
47
|
-
const page = await provider.getThreadHistory("", thread_id, {
|
|
48
|
-
limit: clamped,
|
|
49
|
-
before
|
|
50
|
-
});
|
|
51
|
-
return { content: [{ type: "text", text: JSON.stringify(page) }] };
|
|
52
|
-
}
|
|
53
|
-
);
|
|
54
|
-
server.tool(
|
|
55
|
-
"zooid_get_members",
|
|
56
|
-
"List the humans and agents in the current room.",
|
|
57
|
-
{},
|
|
58
|
-
async () => {
|
|
59
|
-
const provider = await opts.resolve();
|
|
60
|
-
const members = await provider.getChannelMembers("");
|
|
61
|
-
return { content: [{ type: "text", text: JSON.stringify({ members }) }] };
|
|
62
|
-
}
|
|
63
|
-
);
|
|
64
|
-
server.tool(
|
|
65
|
-
"zooid_get_channel_info",
|
|
66
|
-
"Describe the current room: id, display name, transport kind.",
|
|
67
|
-
{},
|
|
68
|
-
async () => {
|
|
69
|
-
const provider = await opts.resolve();
|
|
70
|
-
const info = await provider.getChannelInfo("");
|
|
71
|
-
return { content: [{ type: "text", text: JSON.stringify(info) }] };
|
|
72
|
-
}
|
|
73
|
-
);
|
|
74
|
-
return server;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// src/daemon-socket.ts
|
|
78
|
-
import { createServer, createConnection } from "net";
|
|
79
|
-
import { unlink } from "fs/promises";
|
|
80
|
-
async function startDaemonSocketServer(opts) {
|
|
81
|
-
await unlink(opts.sockPath).catch(() => {
|
|
82
|
-
});
|
|
83
|
-
const server = createServer((socket) => {
|
|
84
|
-
let buf = "";
|
|
85
|
-
socket.setEncoding("utf8");
|
|
86
|
-
socket.on("data", async (chunk) => {
|
|
87
|
-
buf += chunk;
|
|
88
|
-
let idx;
|
|
89
|
-
while ((idx = buf.indexOf("\n")) >= 0) {
|
|
90
|
-
const line = buf.slice(0, idx);
|
|
91
|
-
buf = buf.slice(idx + 1);
|
|
92
|
-
if (!line) continue;
|
|
93
|
-
await handleLine(line, socket, opts.registry);
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
socket.on("error", () => {
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
await new Promise((resolve, reject) => {
|
|
100
|
-
server.once("error", reject);
|
|
101
|
-
server.listen(opts.sockPath, () => {
|
|
102
|
-
server.removeListener("error", reject);
|
|
103
|
-
resolve();
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
return {
|
|
107
|
-
close: () => new Promise((resolve) => {
|
|
108
|
-
server.close(() => resolve());
|
|
109
|
-
})
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
async function handleLine(line, socket, registry) {
|
|
113
|
-
let req;
|
|
114
|
-
try {
|
|
115
|
-
req = JSON.parse(line);
|
|
116
|
-
} catch {
|
|
117
|
-
socket.write(JSON.stringify({ ok: false, error: "invalid json" }) + "\n");
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
const binding = registry.get(req.spawnId);
|
|
121
|
-
if (!binding) {
|
|
122
|
-
process.stderr.write(
|
|
123
|
-
`[context-mcp] daemon: unknown spawn-id ${req.spawnId} for method=${req.method}
|
|
124
|
-
`
|
|
125
|
-
);
|
|
126
|
-
socket.write(
|
|
127
|
-
JSON.stringify({
|
|
128
|
-
ok: false,
|
|
129
|
-
error: `unknown spawn-id: ${req.spawnId}`
|
|
130
|
-
}) + "\n"
|
|
131
|
-
);
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
process.stderr.write(
|
|
135
|
-
`[context-mcp] daemon: ${req.method} spawn=${req.spawnId.slice(0, 8)} agent=${binding.agentName}
|
|
136
|
-
`
|
|
137
|
-
);
|
|
138
|
-
try {
|
|
139
|
-
let result;
|
|
140
|
-
const channelId = binding.threadRef.channelId;
|
|
141
|
-
if (req.method === "getRoomHistory") {
|
|
142
|
-
result = await binding.provider.getRoomHistory(channelId, req.params);
|
|
143
|
-
} else if (req.method === "getRecentThreads") {
|
|
144
|
-
result = await binding.provider.getRecentThreads(channelId, req.params);
|
|
145
|
-
} else if (req.method === "getThreadHistory") {
|
|
146
|
-
const threadId = String(req.params.threadId ?? "");
|
|
147
|
-
result = await binding.provider.getThreadHistory(channelId, threadId, req.params);
|
|
148
|
-
} else if (req.method === "getChannelMembers") {
|
|
149
|
-
result = await binding.provider.getChannelMembers(channelId);
|
|
150
|
-
} else if (req.method === "getChannelInfo") {
|
|
151
|
-
result = await binding.provider.getChannelInfo(channelId);
|
|
152
|
-
} else {
|
|
153
|
-
socket.write(
|
|
154
|
-
JSON.stringify({
|
|
155
|
-
ok: false,
|
|
156
|
-
error: `unknown method: ${req.method}`
|
|
157
|
-
}) + "\n"
|
|
158
|
-
);
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
socket.write(JSON.stringify({ ok: true, result }) + "\n");
|
|
162
|
-
} catch (err) {
|
|
163
|
-
socket.write(
|
|
164
|
-
JSON.stringify({
|
|
165
|
-
ok: false,
|
|
166
|
-
error: String(err instanceof Error ? err.message : err)
|
|
167
|
-
}) + "\n"
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
async function callDaemon(sockPath, req) {
|
|
172
|
-
return new Promise((resolve, reject) => {
|
|
173
|
-
const socket = createConnection(sockPath);
|
|
174
|
-
let buf = "";
|
|
175
|
-
socket.setEncoding("utf8");
|
|
176
|
-
socket.on("error", reject);
|
|
177
|
-
socket.on("data", (chunk) => {
|
|
178
|
-
buf += chunk;
|
|
179
|
-
const idx = buf.indexOf("\n");
|
|
180
|
-
if (idx < 0) return;
|
|
181
|
-
const line = buf.slice(0, idx);
|
|
182
|
-
let parsed;
|
|
183
|
-
try {
|
|
184
|
-
parsed = JSON.parse(line);
|
|
185
|
-
} catch (e) {
|
|
186
|
-
socket.end();
|
|
187
|
-
reject(e instanceof Error ? e : new Error(String(e)));
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
socket.end();
|
|
191
|
-
if (parsed.ok) resolve(parsed.result);
|
|
192
|
-
else reject(new Error(parsed.error));
|
|
193
|
-
});
|
|
194
|
-
socket.write(JSON.stringify(req) + "\n");
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
export {
|
|
199
|
-
buildContextMcpServer,
|
|
200
|
-
startDaemonSocketServer,
|
|
201
|
-
callDaemon
|
|
202
|
-
};
|
|
203
|
-
//# sourceMappingURL=chunk-QQD76TLH.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mcp-server.ts","../src/daemon-socket.ts"],"sourcesContent":["import { z } from 'zod'\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type { TransportContextProvider } from '@zooid/core'\n\nconst MAX_LIMIT = 200\nconst DEFAULT_LIMIT = 50\n\nexport interface BuildContextMcpServerOpts {\n /**\n * Resolves the provider for the current spawn. In production this calls\n * back to the daemon over the Unix socket; in unit tests it returns a\n * fake provider directly.\n */\n resolve: () => Promise<TransportContextProvider>\n}\n\nexport function buildContextMcpServer(opts: BuildContextMcpServerOpts): McpServer {\n const server = new McpServer({ name: 'zooid-context', version: '0.0.1' })\n\n server.tool(\n 'zooid_get_history',\n \"Read every message in the current room chronologically — top-level messages and all thread replies. Each message has an optional `thread_id` so the agent can group by thread. For a scan-the-room overview without reply noise, use `zooid_get_recent_threads` instead. Supports `limit` + `before` pagination.\",\n {\n limit: z.number().int().positive().optional(),\n before: z.string().optional(),\n },\n async ({ limit, before }) => {\n const provider = await opts.resolve()\n const clamped = Math.min(limit ?? DEFAULT_LIMIT, MAX_LIMIT)\n const page = await provider.getRoomHistory('', { limit: clamped, before })\n return { content: [{ type: 'text', text: JSON.stringify(page) }] }\n },\n )\n\n server.tool(\n 'zooid_get_recent_threads',\n \"Scan-the-room overview: top-level messages and thread roots in the current room, newest first. Each entry has `reply_count` and `last_activity_at` so the agent can spot active conversations. Drill into a thread with `zooid_get_thread_history(thread_id)` where `thread_id` is the entry's `id`.\",\n {\n limit: z.number().int().positive().optional(),\n before: z.string().optional(),\n },\n async ({ limit, before }) => {\n const provider = await opts.resolve()\n const clamped = Math.min(limit ?? DEFAULT_LIMIT, MAX_LIMIT)\n const page = await provider.getRecentThreads('', { limit: clamped, before })\n return { content: [{ type: 'text', text: JSON.stringify(page) }] }\n },\n )\n\n server.tool(\n 'zooid_get_thread_history',\n \"Drill into a specific thread: the root message followed by all replies in chronological order. Pass the `thread_id` from a `zooid_get_recent_threads` entry or a `Message.thread_id` from `zooid_get_history`.\",\n {\n thread_id: z.string(),\n limit: z.number().int().positive().optional(),\n before: z.string().optional(),\n },\n async ({ thread_id, limit, before }) => {\n const provider = await opts.resolve()\n const clamped = Math.min(limit ?? DEFAULT_LIMIT, MAX_LIMIT)\n const page = await provider.getThreadHistory('', thread_id, {\n limit: clamped,\n before,\n })\n return { content: [{ type: 'text', text: JSON.stringify(page) }] }\n },\n )\n\n server.tool(\n 'zooid_get_members',\n 'List the humans and agents in the current room.',\n {},\n async () => {\n const provider = await opts.resolve()\n const members = await provider.getChannelMembers('')\n return { content: [{ type: 'text', text: JSON.stringify({ members }) }] }\n },\n )\n\n server.tool(\n 'zooid_get_channel_info',\n 'Describe the current room: id, display name, transport kind.',\n {},\n async () => {\n const provider = await opts.resolve()\n const info = await provider.getChannelInfo('')\n return { content: [{ type: 'text', text: JSON.stringify(info) }] }\n },\n )\n\n return server\n}\n","import { createServer, createConnection, type Server, type Socket } from 'node:net'\nimport { unlink } from 'node:fs/promises'\nimport type { SpawnRegistry } from './spawn-registry.js'\n\ninterface DaemonRequest {\n spawnId: string\n method:\n | 'getRoomHistory'\n | 'getRecentThreads'\n | 'getThreadHistory'\n | 'getChannelMembers'\n | 'getChannelInfo'\n params: Record<string, unknown>\n}\n\ninterface DaemonResponse {\n ok: true\n result: unknown\n}\n\ninterface DaemonError {\n ok: false\n error: string\n}\n\nexport interface DaemonSocketHandle {\n close(): Promise<void>\n}\n\nexport async function startDaemonSocketServer(opts: {\n sockPath: string\n registry: SpawnRegistry\n}): Promise<DaemonSocketHandle> {\n await unlink(opts.sockPath).catch(() => {})\n const server: Server = createServer((socket: Socket) => {\n let buf = ''\n socket.setEncoding('utf8')\n socket.on('data', async (chunk) => {\n buf += chunk\n let idx: number\n while ((idx = buf.indexOf('\\n')) >= 0) {\n const line = buf.slice(0, idx)\n buf = buf.slice(idx + 1)\n if (!line) continue\n await handleLine(line, socket, opts.registry)\n }\n })\n socket.on('error', () => {})\n })\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject)\n server.listen(opts.sockPath, () => {\n server.removeListener('error', reject)\n resolve()\n })\n })\n return {\n close: () =>\n new Promise<void>((resolve) => {\n server.close(() => resolve())\n }),\n }\n}\n\nasync function handleLine(line: string, socket: Socket, registry: SpawnRegistry) {\n let req: DaemonRequest\n try {\n req = JSON.parse(line) as DaemonRequest\n } catch {\n socket.write(JSON.stringify({ ok: false, error: 'invalid json' } satisfies DaemonError) + '\\n')\n return\n }\n const binding = registry.get(req.spawnId)\n if (!binding) {\n process.stderr.write(\n `[context-mcp] daemon: unknown spawn-id ${req.spawnId} for method=${req.method}\\n`,\n )\n socket.write(\n JSON.stringify({\n ok: false,\n error: `unknown spawn-id: ${req.spawnId}`,\n } satisfies DaemonError) + '\\n',\n )\n return\n }\n process.stderr.write(\n `[context-mcp] daemon: ${req.method} spawn=${req.spawnId.slice(0, 8)} agent=${binding.agentName}\\n`,\n )\n try {\n let result: unknown\n const channelId = binding.threadRef.channelId\n if (req.method === 'getRoomHistory') {\n result = await binding.provider.getRoomHistory(channelId, req.params)\n } else if (req.method === 'getRecentThreads') {\n result = await binding.provider.getRecentThreads(channelId, req.params)\n } else if (req.method === 'getThreadHistory') {\n const threadId = String(req.params.threadId ?? '')\n result = await binding.provider.getThreadHistory(channelId, threadId, req.params)\n } else if (req.method === 'getChannelMembers') {\n result = await binding.provider.getChannelMembers(channelId)\n } else if (req.method === 'getChannelInfo') {\n result = await binding.provider.getChannelInfo(channelId)\n } else {\n socket.write(\n JSON.stringify({\n ok: false,\n error: `unknown method: ${(req as { method: string }).method}`,\n } satisfies DaemonError) + '\\n',\n )\n return\n }\n socket.write(JSON.stringify({ ok: true, result } satisfies DaemonResponse) + '\\n')\n } catch (err) {\n socket.write(\n JSON.stringify({\n ok: false,\n error: String(err instanceof Error ? err.message : err),\n } satisfies DaemonError) + '\\n',\n )\n }\n}\n\nexport async function callDaemon(sockPath: string, req: DaemonRequest): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const socket = createConnection(sockPath)\n let buf = ''\n socket.setEncoding('utf8')\n socket.on('error', reject)\n socket.on('data', (chunk) => {\n buf += chunk\n const idx = buf.indexOf('\\n')\n if (idx < 0) return\n const line = buf.slice(0, idx)\n let parsed: DaemonResponse | DaemonError\n try {\n parsed = JSON.parse(line) as DaemonResponse | DaemonError\n } catch (e) {\n socket.end()\n reject(e instanceof Error ? e : new Error(String(e)))\n return\n }\n socket.end()\n if (parsed.ok) resolve(parsed.result)\n else reject(new Error(parsed.error))\n })\n socket.write(JSON.stringify(req) + '\\n')\n })\n}\n"],"mappings":"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","names":[]}
|