zooid 0.8.0 → 0.9.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 +5 -5
- package/dist/bin.js +16 -17
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-R6EDLH23.js → chunk-LOILUENL.js} +130 -52
- package/dist/{chunk-R6EDLH23.js.map → chunk-LOILUENL.js.map} +1 -1
- package/dist/index.js +1 -1
- package/package.json +10 -10
- package/src/bin.ts +1 -1
- package/src/commands/dev.ts +8 -8
- package/src/daemon/start-daemon.ts +9 -9
- package/src/web/fetch.integration.test.ts +4 -4
- package/src/web/fetch.test.ts +4 -4
- package/src/web/fetch.ts +2 -2
- package/src/web/pin.test.ts +2 -2
- package/src/web/pin.ts +2 -2
- package/src/web/resolve.test.ts +3 -3
- package/src/web/resolve.ts +3 -3
- package/src/web/test-helpers.ts +1 -1
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zooid",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.9.0",
|
|
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",
|
|
7
7
|
"private": false,
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"access": "public"
|
|
26
26
|
},
|
|
27
27
|
"zooid": {
|
|
28
|
-
"
|
|
28
|
+
"webVersion": "0.7.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/context-mcp": "^0.
|
|
45
|
-
"@zooid/
|
|
46
|
-
"@zooid/acp-client": "^0.
|
|
47
|
-
"@zooid/
|
|
48
|
-
"@zooid/
|
|
49
|
-
"@zooid/
|
|
50
|
-
"@zooid/
|
|
44
|
+
"@zooid/context-mcp": "^0.9.0",
|
|
45
|
+
"@zooid/runtime-docker": "^0.9.0",
|
|
46
|
+
"@zooid/acp-client": "^0.9.0",
|
|
47
|
+
"@zooid/runtime-local": "^0.9.0",
|
|
48
|
+
"@zooid/core": "^0.9.0",
|
|
49
|
+
"@zooid/transport-matrix": "^0.9.0",
|
|
50
|
+
"@zooid/transport-http": "^0.9.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@agentclientprotocol/sdk": "^0.21.0",
|
package/src/bin.ts
CHANGED
|
@@ -33,7 +33,7 @@ cli
|
|
|
33
33
|
.option('--admin-password <pw>', 'Admin password', { default: 'admin' })
|
|
34
34
|
.option(
|
|
35
35
|
'--watch-web [path]',
|
|
36
|
-
'Run vite build --watch on @zooid/
|
|
36
|
+
'Run vite build --watch on @zooid/web. Path defaults to sibling ../zooid-clients/packages/web.',
|
|
37
37
|
)
|
|
38
38
|
.action(async (flags) => {
|
|
39
39
|
await runDev({
|
package/src/commands/dev.ts
CHANGED
|
@@ -67,8 +67,8 @@ export interface DevFlags {
|
|
|
67
67
|
adminPassword: string
|
|
68
68
|
installSignalHandlers?: boolean
|
|
69
69
|
foreground?: boolean
|
|
70
|
-
// Run `vite build --watch` against a @zooid/
|
|
71
|
-
// true = auto-detect (sibling ../
|
|
70
|
+
// Run `vite build --watch` against a @zooid/web package and serve its dist.
|
|
71
|
+
// true = auto-detect (sibling ../zooid-clients/packages/web or in-monorepo); string = explicit path.
|
|
72
72
|
watchWeb?: string | boolean
|
|
73
73
|
}
|
|
74
74
|
|
|
@@ -217,17 +217,17 @@ export async function runDev(flags: DevFlags): Promise<DevHandle> {
|
|
|
217
217
|
...(flags.watchWeb
|
|
218
218
|
? [
|
|
219
219
|
{
|
|
220
|
-
title: 'Start @zooid/
|
|
220
|
+
title: 'Start @zooid/web watcher (vite build --watch)',
|
|
221
221
|
task: async (): Promise<void> => {
|
|
222
222
|
const pkgDir =
|
|
223
223
|
typeof flags.watchWeb === 'string'
|
|
224
224
|
? resolve(flags.watchWeb)
|
|
225
225
|
: webSourcePackage(CLI_ROOT)
|
|
226
226
|
if (!pkgDir) {
|
|
227
|
-
const defaultPath = dirname(dirname(dirname(CLI_ROOT))) + '/
|
|
227
|
+
const defaultPath = dirname(dirname(dirname(CLI_ROOT))) + '/zooid-clients/packages/web'
|
|
228
228
|
throw new Error(
|
|
229
|
-
`--watch-web: @zooid/
|
|
230
|
-
`Pass an explicit path: --watch-web=/path/to/
|
|
229
|
+
`--watch-web: @zooid/web not found at ${defaultPath}.\n` +
|
|
230
|
+
`Pass an explicit path: --watch-web=/path/to/zooid-clients/packages/web`,
|
|
231
231
|
)
|
|
232
232
|
}
|
|
233
233
|
ctx.webWatch = await startWebWatch({ webPackageDir: pkgDir })
|
|
@@ -236,7 +236,7 @@ export async function runDev(flags: DevFlags): Promise<DevHandle> {
|
|
|
236
236
|
]
|
|
237
237
|
: []),
|
|
238
238
|
{
|
|
239
|
-
title: `Serve @zooid/
|
|
239
|
+
title: `Serve @zooid/web on http://localhost:${flags.uiPort}`,
|
|
240
240
|
task: async (_, t) => {
|
|
241
241
|
const webRoot =
|
|
242
242
|
ctx.webWatch?.distPath ??
|
|
@@ -304,7 +304,7 @@ export async function runDev(flags: DevFlags): Promise<DevHandle> {
|
|
|
304
304
|
` ${chalk.cyan('admin user:')} ${flags.adminUser} / ${flags.adminPassword}`,
|
|
305
305
|
` ${chalk.cyan('data dir:')} ${layout.dataRoot}`,
|
|
306
306
|
...(ctx.webWatch
|
|
307
|
-
? [` ${chalk.cyan('web watcher:')} live (vite build --watch on @zooid/
|
|
307
|
+
? [` ${chalk.cyan('web watcher:')} live (vite build --watch on @zooid/web)`]
|
|
308
308
|
: []),
|
|
309
309
|
'',
|
|
310
310
|
chalk.dim('Press Ctrl-C to stop.'),
|
|
@@ -184,6 +184,13 @@ export async function startDaemon(opts: StartDaemonOpts = {}): Promise<DaemonHan
|
|
|
184
184
|
binding.agentWorkspacePath = isContainerRuntime ? '/workspace' : workspaceDir
|
|
185
185
|
bindings.push(binding)
|
|
186
186
|
}
|
|
187
|
+
// user_namespace is a regex like `@.*:localhost`; the part after the last
|
|
188
|
+
// `:` is the homeserver's server_name. Fall back to the homeserver URL's
|
|
189
|
+
// host if the namespace shape is unexpected.
|
|
190
|
+
const serverName =
|
|
191
|
+
matrix.transport.user_namespace.split(':').slice(1).join(':').replace(/\\?\)?$/, '') ||
|
|
192
|
+
new URL(matrix.transport.homeserver).hostname
|
|
193
|
+
const asUserId = `@${matrix.transport.sender_localpart}:${serverName}`
|
|
187
194
|
const transport = createMatrixTransport({
|
|
188
195
|
agents: registry,
|
|
189
196
|
approvals,
|
|
@@ -191,6 +198,7 @@ export async function startDaemon(opts: StartDaemonOpts = {}): Promise<DaemonHan
|
|
|
191
198
|
bindings,
|
|
192
199
|
hsToken: matrix.transport.hs_token,
|
|
193
200
|
adminUserId: opts.adminUserId,
|
|
201
|
+
botUserId: asUserId,
|
|
194
202
|
media: mediaClient,
|
|
195
203
|
})
|
|
196
204
|
const requestedPort = matrix.transport.port ?? 9000
|
|
@@ -199,14 +207,6 @@ export async function startDaemon(opts: StartDaemonOpts = {}): Promise<DaemonHan
|
|
|
199
207
|
// events back to host.docker.internal:<port>.
|
|
200
208
|
server = serve({ fetch: transport.app.fetch, port: requestedPort, hostname: '0.0.0.0' })
|
|
201
209
|
port = await listenAsync(server)
|
|
202
|
-
|
|
203
|
-
// user_namespace is a regex like `@.*:localhost`; the part after the last
|
|
204
|
-
// `:` is the homeserver's server_name. Fall back to the homeserver URL's
|
|
205
|
-
// host if the namespace shape is unexpected.
|
|
206
|
-
const serverName =
|
|
207
|
-
matrix.transport.user_namespace.split(':').slice(1).join(':').replace(/\\?\)?$/, '') ||
|
|
208
|
-
new URL(matrix.transport.homeserver).hostname
|
|
209
|
-
const asUserId = `@${matrix.transport.sender_localpart}:${serverName}`
|
|
210
210
|
const spaceLocalpart = matrix.transport.space ?? 'dev'
|
|
211
211
|
const adminUserIds = opts.adminUserId ? [opts.adminUserId] : []
|
|
212
212
|
let spaceRoomId: string | undefined
|
|
@@ -253,7 +253,7 @@ export async function startDaemon(opts: StartDaemonOpts = {}): Promise<DaemonHan
|
|
|
253
253
|
asUserId,
|
|
254
254
|
getAgents: () => bindings,
|
|
255
255
|
})
|
|
256
|
-
console.log(`[matrix] published
|
|
256
|
+
console.log(`[matrix] published dev.zooid.workforce (${bindings.length} agents)`)
|
|
257
257
|
void publisher
|
|
258
258
|
} catch (err) {
|
|
259
259
|
console.warn('[matrix] workforce roster publication failed:', err)
|
|
@@ -10,26 +10,26 @@ import { makeBundleTgz } from './test-helpers.js'
|
|
|
10
10
|
let server: Server
|
|
11
11
|
let base = ''
|
|
12
12
|
const { tgz, integrity } = makeBundleTgz({
|
|
13
|
-
'package/package.json': '{"name":"@zooid/
|
|
13
|
+
'package/package.json': '{"name":"@zooid/web"}',
|
|
14
14
|
'package/dist/index.html': '<html>integration</html>',
|
|
15
15
|
})
|
|
16
16
|
|
|
17
17
|
beforeAll(async () => {
|
|
18
18
|
server = createServer((req, res) => {
|
|
19
|
-
if (req.url === '/@zooid/
|
|
19
|
+
if (req.url === '/@zooid/web') {
|
|
20
20
|
res.setHeader('content-type', 'application/json')
|
|
21
21
|
res.end(
|
|
22
22
|
JSON.stringify({
|
|
23
23
|
versions: {
|
|
24
24
|
'0.1.0': {
|
|
25
|
-
dist: { tarball: `${base}/@zooid/
|
|
25
|
+
dist: { tarball: `${base}/@zooid/web/-/web-0.1.0.tgz`, integrity },
|
|
26
26
|
},
|
|
27
27
|
},
|
|
28
28
|
}),
|
|
29
29
|
)
|
|
30
30
|
return
|
|
31
31
|
}
|
|
32
|
-
if (req.url === '/@zooid/
|
|
32
|
+
if (req.url === '/@zooid/web/-/web-0.1.0.tgz') {
|
|
33
33
|
res.setHeader('content-type', 'application/octet-stream')
|
|
34
34
|
res.end(tgz)
|
|
35
35
|
return
|
package/src/web/fetch.test.ts
CHANGED
|
@@ -9,14 +9,14 @@ function registryFetch(opts: { tgz: Buffer; integrity: string; version?: string
|
|
|
9
9
|
const version = opts.version ?? '0.1.0'
|
|
10
10
|
return vi.fn(async (url: string | URL) => {
|
|
11
11
|
const u = String(url)
|
|
12
|
-
if (u === 'https://registry.npmjs.org/@zooid/
|
|
12
|
+
if (u === 'https://registry.npmjs.org/@zooid/web') {
|
|
13
13
|
return new Response(
|
|
14
14
|
JSON.stringify({
|
|
15
15
|
'dist-tags': { latest: version },
|
|
16
16
|
versions: {
|
|
17
17
|
[version]: {
|
|
18
18
|
dist: {
|
|
19
|
-
tarball: `https://registry.npmjs.org/@zooid/
|
|
19
|
+
tarball: `https://registry.npmjs.org/@zooid/web/-/web-${version}.tgz`,
|
|
20
20
|
integrity: opts.integrity,
|
|
21
21
|
},
|
|
22
22
|
},
|
|
@@ -25,7 +25,7 @@ function registryFetch(opts: { tgz: Buffer; integrity: string; version?: string
|
|
|
25
25
|
{ status: 200 },
|
|
26
26
|
)
|
|
27
27
|
}
|
|
28
|
-
if (u.endsWith(`/
|
|
28
|
+
if (u.endsWith(`/web-${version}.tgz`)) {
|
|
29
29
|
return new Response(new Uint8Array(opts.tgz), { status: 200 })
|
|
30
30
|
}
|
|
31
31
|
return new Response('not found', { status: 404 })
|
|
@@ -86,7 +86,7 @@ describe('fetchWebBundle', () => {
|
|
|
86
86
|
const { tgz, integrity } = makeBundleTgz()
|
|
87
87
|
const f = registryFetch({ tgz, integrity, version: '0.0.9' })
|
|
88
88
|
await expect(fetchWebBundle({ version: '0.1.0', cacheDir, fetch: f })).rejects.toThrow(
|
|
89
|
-
/@zooid\/
|
|
89
|
+
/@zooid\/web@0\.1\.0/,
|
|
90
90
|
)
|
|
91
91
|
} finally {
|
|
92
92
|
teardown()
|
package/src/web/fetch.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { join } from 'node:path'
|
|
|
3
3
|
import { createHash, randomUUID } from 'node:crypto'
|
|
4
4
|
import * as tar from 'tar'
|
|
5
5
|
|
|
6
|
-
const PKG = '@zooid/
|
|
6
|
+
const PKG = '@zooid/web'
|
|
7
7
|
const DEFAULT_REGISTRY = 'https://registry.npmjs.org'
|
|
8
8
|
|
|
9
9
|
export interface FetchWebBundleOptions {
|
|
@@ -14,7 +14,7 @@ export interface FetchWebBundleOptions {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* Ensure <cacheDir>/<version> holds the extracted dist/ of @zooid/
|
|
17
|
+
* Ensure <cacheDir>/<version> holds the extracted dist/ of @zooid/web.
|
|
18
18
|
* Atomic: extracts into a temp dir and renames, so a crash never leaves a
|
|
19
19
|
* half-populated version dir. A populated version dir (index.html present)
|
|
20
20
|
* is the completion marker.
|
package/src/web/pin.test.ts
CHANGED
|
@@ -9,10 +9,10 @@ beforeEach(() => (dir = mkdtempSync(join(tmpdir(), 'zooid-pin-'))))
|
|
|
9
9
|
afterEach(() => rmSync(dir, { recursive: true, force: true }))
|
|
10
10
|
|
|
11
11
|
describe('readZoonWebPin', () => {
|
|
12
|
-
it('reads zooid.
|
|
12
|
+
it('reads zooid.webVersion from the cli package.json', () => {
|
|
13
13
|
writeFileSync(
|
|
14
14
|
join(dir, 'package.json'),
|
|
15
|
-
JSON.stringify({ name: 'zooid', zooid: {
|
|
15
|
+
JSON.stringify({ name: 'zooid', zooid: { webVersion: '0.1.0' } }),
|
|
16
16
|
)
|
|
17
17
|
expect(readZoonWebPin(dir)).toBe('0.1.0')
|
|
18
18
|
})
|
package/src/web/pin.ts
CHANGED
|
@@ -4,9 +4,9 @@ import { join } from 'node:path'
|
|
|
4
4
|
export function readZoonWebPin(cliRoot: string): string | undefined {
|
|
5
5
|
try {
|
|
6
6
|
const pkg = JSON.parse(readFileSync(join(cliRoot, 'package.json'), 'utf8')) as {
|
|
7
|
-
zooid?: {
|
|
7
|
+
zooid?: { webVersion?: string }
|
|
8
8
|
}
|
|
9
|
-
return pkg.zooid?.
|
|
9
|
+
return pkg.zooid?.webVersion
|
|
10
10
|
} catch {
|
|
11
11
|
return undefined
|
|
12
12
|
}
|
package/src/web/resolve.test.ts
CHANGED
|
@@ -19,7 +19,7 @@ function makeSibling(rootDir: string): { cliRoot: string; webDist: string } {
|
|
|
19
19
|
const webPkg = join(rootDir, 'zoon', 'packages', 'web')
|
|
20
20
|
const webDist = join(webPkg, 'dist')
|
|
21
21
|
mkdirSync(webDist, { recursive: true })
|
|
22
|
-
writeFileSync(join(webPkg, 'package.json'), '{"name":"@zooid/
|
|
22
|
+
writeFileSync(join(webPkg, 'package.json'), '{"name":"@zooid/web"}')
|
|
23
23
|
writeFileSync(join(webDist, 'index.html'), '<html/>')
|
|
24
24
|
return { cliRoot, webDist }
|
|
25
25
|
}
|
|
@@ -62,12 +62,12 @@ describe('ensureWebRoot', () => {
|
|
|
62
62
|
mkdirSync(cliRoot, { recursive: true })
|
|
63
63
|
await expect(
|
|
64
64
|
ensureWebRoot({ cliRoot, cacheDir: join(root, 'cache'), version: undefined, fetchBundle: vi.fn() }),
|
|
65
|
-
).rejects.toThrow(/
|
|
65
|
+
).rejects.toThrow(/webVersion/)
|
|
66
66
|
})
|
|
67
67
|
})
|
|
68
68
|
|
|
69
69
|
describe('webSourcePackage', () => {
|
|
70
|
-
it('returns the source package dir when sibling
|
|
70
|
+
it('returns the source package dir when sibling zooid-clients/packages/web exists', () => {
|
|
71
71
|
const { cliRoot } = makeSibling(root)
|
|
72
72
|
expect(webSourcePackage(cliRoot)).toBe(join(root, 'zoon', 'packages', 'web'))
|
|
73
73
|
})
|
package/src/web/resolve.ts
CHANGED
|
@@ -23,17 +23,17 @@ export async function ensureWebRoot(opts: EnsureWebRootOptions): Promise<string>
|
|
|
23
23
|
|
|
24
24
|
if (!opts.version) {
|
|
25
25
|
throw new Error(
|
|
26
|
-
`No @zooid/
|
|
26
|
+
`No @zooid/web version pin (zooid.webVersion) in the cli package.json ` +
|
|
27
27
|
`and no monorepo sibling build found.\n` +
|
|
28
28
|
`Set ${ENV_OVERRIDE} to a built dist, or run from the monorepo.`,
|
|
29
29
|
)
|
|
30
30
|
}
|
|
31
|
-
opts.onProgress?.(`Fetching @zooid/
|
|
31
|
+
opts.onProgress?.(`Fetching @zooid/web ${opts.version}…`)
|
|
32
32
|
const fetchBundleFn = opts.fetchBundle ?? fetchWebBundle
|
|
33
33
|
return fetchBundleFn({ version: opts.version, cacheDir: opts.cacheDir })
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
// Returns the path to the in-tree @zooid/
|
|
36
|
+
// Returns the path to the in-tree @zooid/web package (zooid-clients/packages/web) if the
|
|
37
37
|
// CLI is running from the monorepo source. Returns null when running from an
|
|
38
38
|
// installed package (no sibling zoon/ tree).
|
|
39
39
|
export function webSourcePackage(cliRoot: string): string | null {
|
package/src/web/test-helpers.ts
CHANGED
|
@@ -6,7 +6,7 @@ import * as tar from 'tar'
|
|
|
6
6
|
|
|
7
7
|
export function makeBundleTgz(
|
|
8
8
|
files: Record<string, string> = {
|
|
9
|
-
'package/package.json': '{"name":"@zooid/
|
|
9
|
+
'package/package.json': '{"name":"@zooid/web"}',
|
|
10
10
|
'package/dist/index.html': '<html>zoon</html>',
|
|
11
11
|
'package/dist/assets/app.js': '// app',
|
|
12
12
|
},
|