zooid 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/README.md +35 -9
- package/dist/bin.js +1 -1
- package/dist/{chunk-PDSJJWQW.js → chunk-OCRQ3LWL.js} +80 -31
- package/dist/chunk-OCRQ3LWL.js.map +1 -0
- package/dist/index.js +1 -1
- package/package.json +9 -9
- package/src/build-registry.context.test.ts +51 -0
- package/src/build-registry.ts +20 -2
- package/dist/chunk-PDSJJWQW.js.map +0 -1
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zooid",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "An open-source, self-hostable chat app for collaborating with AI agents alongside your team. Any model, any CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"access": "public"
|
|
26
26
|
},
|
|
27
27
|
"zooid": {
|
|
28
|
-
"webVersion": "0.
|
|
28
|
+
"webVersion": "0.9.0"
|
|
29
29
|
},
|
|
30
30
|
"engines": {
|
|
31
31
|
"node": ">=22"
|
|
@@ -41,13 +41,13 @@
|
|
|
41
41
|
"sanitize-html": "^2.17.4",
|
|
42
42
|
"tar": "^7.5.16",
|
|
43
43
|
"yaml": "^2.5.0",
|
|
44
|
-
"@zooid/acp-client": "^0.
|
|
45
|
-
"@zooid/context-mcp": "^0.
|
|
46
|
-
"@zooid/core": "^0.
|
|
47
|
-
"@zooid/runtime-
|
|
48
|
-
"@zooid/runtime-
|
|
49
|
-
"@zooid/transport-http": "^0.
|
|
50
|
-
"@zooid/transport-matrix": "^0.
|
|
44
|
+
"@zooid/acp-client": "^0.11.0",
|
|
45
|
+
"@zooid/context-mcp": "^0.11.0",
|
|
46
|
+
"@zooid/core": "^0.11.0",
|
|
47
|
+
"@zooid/runtime-local": "^0.11.0",
|
|
48
|
+
"@zooid/runtime-docker": "^0.11.0",
|
|
49
|
+
"@zooid/transport-http": "^0.11.0",
|
|
50
|
+
"@zooid/transport-matrix": "^0.11.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@agentclientprotocol/sdk": "^0.21.0",
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { describe, it, expect, vi } from 'vitest'
|
|
2
2
|
import { buildAcpRegistry } from './build-registry.js'
|
|
3
3
|
import type { ZooidConfig } from '@zooid/core'
|
|
4
|
+
import {
|
|
5
|
+
CONTEXT_CONTAINER_BIN,
|
|
6
|
+
CONTEXT_CONTAINER_BIN_DIR,
|
|
7
|
+
CONTEXT_CONTAINER_SOCK,
|
|
8
|
+
} from '@zooid/context-mcp'
|
|
4
9
|
|
|
5
10
|
const matrixCfg: ZooidConfig = {
|
|
6
11
|
runtime: 'local',
|
|
@@ -59,3 +64,49 @@ describe('buildAcpRegistry — context provider wiring', () => {
|
|
|
59
64
|
expect(registry.hasContextSpawn('architect')).toBe(false)
|
|
60
65
|
})
|
|
61
66
|
})
|
|
67
|
+
|
|
68
|
+
describe('buildAcpRegistry — context provider in a container runtime', () => {
|
|
69
|
+
function podmanCfg(): ZooidConfig {
|
|
70
|
+
const cfg = structuredClone(matrixCfg)
|
|
71
|
+
cfg.runtime = 'podman'
|
|
72
|
+
// podman requires a resolvable image per agent (no preset here).
|
|
73
|
+
;(cfg.agents.architect as { container?: unknown }).container = { image: 'img:latest' }
|
|
74
|
+
return cfg
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const opts = {
|
|
78
|
+
approvals: { register: vi.fn(), on: vi.fn() } as never,
|
|
79
|
+
contextSpawnRegistry: { register: vi.fn(() => 'spawn-1') } as never,
|
|
80
|
+
daemonSockPath: '/home/ubuntu/hq/data/run/context.sock',
|
|
81
|
+
daemonHome: '/home/ubuntu',
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
it('adds the socket (rw) and bin (ro) bind-mounts to a context-enabled agent', () => {
|
|
85
|
+
const registry = buildAcpRegistry(podmanCfg(), opts)
|
|
86
|
+
const mounts = registry.resolveSpawnMounts('architect')
|
|
87
|
+
const sock = mounts.find((m) => m.target === CONTEXT_CONTAINER_SOCK)
|
|
88
|
+
const bin = mounts.find((m) => m.target === CONTEXT_CONTAINER_BIN_DIR)
|
|
89
|
+
expect(sock).toMatchObject({ path: '/home/ubuntu/hq/data/run/context.sock', mode: 'rw' })
|
|
90
|
+
expect(bin?.mode).toBe('ro')
|
|
91
|
+
expect(bin?.path).toMatch(/context-mcp[/\\]dist$/)
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it('threads a containerized mcpServers spec into the agent factory', async () => {
|
|
95
|
+
const registry = buildAcpRegistry(podmanCfg(), opts)
|
|
96
|
+
// opts is public readonly on the registry; the per-agent factory lives here.
|
|
97
|
+
const factory = registry.opts.contextSpawns!.architect!
|
|
98
|
+
const spec = await factory('!r:hs')
|
|
99
|
+
expect(spec.command).toBe('node')
|
|
100
|
+
expect(spec.args[0]).toBe(CONTEXT_CONTAINER_BIN)
|
|
101
|
+
expect(spec.env).toContainEqual({ name: 'ZOOID_DAEMON_SOCK', value: CONTEXT_CONTAINER_SOCK })
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it('leaves the local runtime host-shaped (no context mounts, host command)', async () => {
|
|
105
|
+
// matrixCfg is runtime: local. No container mounts; factory stays host-shaped.
|
|
106
|
+
const registry = buildAcpRegistry(matrixCfg, opts)
|
|
107
|
+
const mounts = registry.resolveSpawnMounts('architect')
|
|
108
|
+
expect(mounts.some((m) => m.target === CONTEXT_CONTAINER_SOCK)).toBe(false)
|
|
109
|
+
const spec = await registry.opts.contextSpawns!.architect!('!r:hs')
|
|
110
|
+
expect(spec.command).toBe(process.execPath)
|
|
111
|
+
})
|
|
112
|
+
})
|
package/src/build-registry.ts
CHANGED
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
type TransportContextProvider,
|
|
15
15
|
} from '@zooid/core'
|
|
16
16
|
import { MatrixClient, MatrixContextProvider } from '@zooid/transport-matrix'
|
|
17
|
-
import { SpawnRegistry, buildContextServerSpec } from '@zooid/context-mcp'
|
|
17
|
+
import { SpawnRegistry, buildContextServerSpec, contextContainerMounts } from '@zooid/context-mcp'
|
|
18
18
|
import { PRESETS, type PresetMount, type PresetName } from '@zooid/acp-client'
|
|
19
19
|
|
|
20
20
|
export interface BuildAcpRegistryOptions {
|
|
@@ -271,6 +271,20 @@ export function buildAcpRegistry(
|
|
|
271
271
|
|
|
272
272
|
const contextSpawns = buildContextSpawns(cfg, opts)
|
|
273
273
|
|
|
274
|
+
// Container runtimes: opencode spawns the zooid-context MCP subprocess INSIDE
|
|
275
|
+
// its container, so the daemon socket + the (self-contained) bin must be
|
|
276
|
+
// bind-mounted in. Local runtime needs neither — the host spec resolves
|
|
277
|
+
// directly. Only agents that actually got a context factory get the mounts.
|
|
278
|
+
if (cfg.runtime !== 'local' && opts.daemonSockPath && contextSpawns) {
|
|
279
|
+
for (const name of Object.keys(cfg.agents)) {
|
|
280
|
+
if (!contextSpawns[name]) continue
|
|
281
|
+
mountsByAgent[name] = [
|
|
282
|
+
...(mountsByAgent[name] ?? []),
|
|
283
|
+
...contextContainerMounts({ sockPath: opts.daemonSockPath }),
|
|
284
|
+
]
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
274
288
|
return new AcpAgentRegistry({
|
|
275
289
|
runtime,
|
|
276
290
|
agents: cfg.agents,
|
|
@@ -322,7 +336,11 @@ function buildContextSpawns(
|
|
|
322
336
|
threadRef: { channelId: channelId ?? threadId, threadId },
|
|
323
337
|
provider,
|
|
324
338
|
})
|
|
325
|
-
return buildContextServerSpec({
|
|
339
|
+
return buildContextServerSpec({
|
|
340
|
+
spawnId,
|
|
341
|
+
sockPath,
|
|
342
|
+
containerize: cfg.runtime !== 'local',
|
|
343
|
+
})
|
|
326
344
|
}
|
|
327
345
|
} else {
|
|
328
346
|
result[name] = undefined
|