zooid 0.13.0 → 0.14.1
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 +6 -1
- package/dist/bin.js +689 -171
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-YZ4IO5MR.js → chunk-R5S26T7B.js} +20523 -507
- package/dist/chunk-R5S26T7B.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/package.json +11 -9
- package/src/build-registry.context.test.ts +3 -3
- package/src/build-registry.ts +67 -24
- package/src/daemon/delivery-cache.test.ts +34 -0
- package/src/daemon/delivery-cache.ts +36 -0
- package/src/daemon/load-custom-verifiers.ts +43 -0
- package/src/daemon/start-daemon.ts +162 -38
- package/src/daemon/task-journal.test.ts +19 -0
- package/src/daemon/task-journal.ts +32 -0
- package/src/daemon/trigger-rooms.test.ts +60 -0
- package/src/daemon/trigger-rooms.ts +0 -0
- package/src/daemon/trigger-runner.test.ts +71 -0
- package/src/daemon/trigger-runner.ts +41 -0
- package/src/daemon/trigger-scheduler.ts +55 -0
- package/src/daemon/webhook-routes.test.ts +104 -0
- package/src/daemon/webhook-routes.ts +237 -0
- package/src/daemon/webhook-verify.test.ts +155 -0
- package/src/daemon/webhook-verify.ts +155 -0
- package/src/pi-extension-install.test.ts +65 -0
- package/src/pi-extension-install.ts +56 -0
- package/dist/chunk-YZ4IO5MR.js.map +0 -1
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it } from 'vitest'
|
|
2
|
+
import { existsSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
|
3
|
+
import { tmpdir } from 'node:os'
|
|
4
|
+
import { join } from 'node:path'
|
|
5
|
+
import { installPiExtension, resolvePiAgentDir } from './pi-extension-install.js'
|
|
6
|
+
|
|
7
|
+
const dirs: string[] = []
|
|
8
|
+
const scratch = () => { const dir = mkdtempSync(join(tmpdir(), 'zooid-pi-')); dirs.push(dir); return dir }
|
|
9
|
+
afterEach(() => dirs.splice(0).forEach((dir) => rmSync(dir, { recursive: true, force: true })))
|
|
10
|
+
|
|
11
|
+
describe('resolvePiAgentDir', () => {
|
|
12
|
+
it('resolves a relative PI_CODING_AGENT_DIR against each agent workdir', () => {
|
|
13
|
+
expect(
|
|
14
|
+
resolvePiAgentDir({
|
|
15
|
+
agentWorkdir: '/proj/agents/alice',
|
|
16
|
+
daemonHome: '/home/op',
|
|
17
|
+
env: { PI_CODING_AGENT_DIR: '.pi-agent' },
|
|
18
|
+
}),
|
|
19
|
+
).toEqual({ dir: '/proj/agents/alice/.pi-agent', scope: 'project' })
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('honours an absolute override and falls back to the operator home', () => {
|
|
23
|
+
expect(
|
|
24
|
+
resolvePiAgentDir({
|
|
25
|
+
agentWorkdir: '/proj/agents/alice',
|
|
26
|
+
daemonHome: '/home/op',
|
|
27
|
+
env: { PI_CODING_AGENT_DIR: '/shared/pi' },
|
|
28
|
+
}),
|
|
29
|
+
).toEqual({ dir: '/shared/pi', scope: 'project' })
|
|
30
|
+
expect(
|
|
31
|
+
resolvePiAgentDir({ agentWorkdir: '/proj/agents/alice', daemonHome: '/home/op', env: {} }),
|
|
32
|
+
).toEqual({ dir: '/home/op/.pi/agent', scope: 'home' })
|
|
33
|
+
})
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
describe('installPiExtension', () => {
|
|
37
|
+
it('only installs into an existing Pi home and preserves other extensions', () => {
|
|
38
|
+
const home = scratch(); const source = join(scratch(), 'bundle.js')
|
|
39
|
+
writeFileSync(source, '// bundle')
|
|
40
|
+
const agentDir = join(home, '.pi', 'agent')
|
|
41
|
+
expect(installPiExtension({ agentDir, bundlePath: source })).toMatchObject({ status: 'skipped' })
|
|
42
|
+
expect(existsSync(join(home, '.pi'))).toBe(false)
|
|
43
|
+
const extensions = join(agentDir, 'extensions')
|
|
44
|
+
mkdirSync(extensions, { recursive: true }); writeFileSync(join(extensions, 'user.js'), '// user')
|
|
45
|
+
expect(installPiExtension({ agentDir, bundlePath: source })).toMatchObject({ status: 'installed' })
|
|
46
|
+
expect(readFileSync(join(extensions, 'zooid-tasks.js'), 'utf8')).toBe('// bundle')
|
|
47
|
+
expect(readFileSync(join(extensions, 'user.js'), 'utf8')).toBe('// user')
|
|
48
|
+
expect(installPiExtension({ agentDir, bundlePath: source })).toMatchObject({ status: 'unchanged' })
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('creates a project agent dir that does not exist yet', () => {
|
|
52
|
+
const workdir = scratch(); const source = join(scratch(), 'bundle.js')
|
|
53
|
+
writeFileSync(source, '// bundle')
|
|
54
|
+
const { dir } = resolvePiAgentDir({
|
|
55
|
+
agentWorkdir: workdir,
|
|
56
|
+
daemonHome: '/home/op',
|
|
57
|
+
env: { PI_CODING_AGENT_DIR: '.pi-agent' },
|
|
58
|
+
})
|
|
59
|
+
expect(installPiExtension({ agentDir: dir, bundlePath: source, createMissing: true })).toMatchObject({
|
|
60
|
+
status: 'installed',
|
|
61
|
+
target: join(workdir, '.pi-agent', 'extensions', 'zooid-tasks.js'),
|
|
62
|
+
})
|
|
63
|
+
expect(readFileSync(join(workdir, '.pi-agent', 'extensions', 'zooid-tasks.js'), 'utf8')).toBe('// bundle')
|
|
64
|
+
})
|
|
65
|
+
})
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import { dirname, isAbsolute, join, resolve } from 'node:path'
|
|
3
|
+
|
|
4
|
+
export interface InstallPiExtensionResult {
|
|
5
|
+
status: 'installed' | 'unchanged' | 'skipped'
|
|
6
|
+
reason?: string
|
|
7
|
+
target?: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface PiAgentDir {
|
|
11
|
+
dir: string
|
|
12
|
+
/** `project` dirs are ours to create; `home` is the operator's ~/.pi. */
|
|
13
|
+
scope: 'project' | 'home'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Resolve pi's agent dir the way pi does: PI_CODING_AGENT_DIR when set,
|
|
18
|
+
* otherwise ~/.pi/agent. `zooid init` writes that variable as a *relative*
|
|
19
|
+
* path on purpose (ZOD075) so one value is correct under both runtimes — it
|
|
20
|
+
* resolves against the agent's cwd, and `agents/<name>` locally and
|
|
21
|
+
* `/workspace` in a container are the same directory. We always resolve
|
|
22
|
+
* against the host workdir, which is the host side of that same mount.
|
|
23
|
+
*/
|
|
24
|
+
export function resolvePiAgentDir(opts: {
|
|
25
|
+
agentWorkdir: string
|
|
26
|
+
daemonHome: string
|
|
27
|
+
env?: { PI_CODING_AGENT_DIR?: string | undefined }
|
|
28
|
+
}): PiAgentDir {
|
|
29
|
+
const override = opts.env?.PI_CODING_AGENT_DIR
|
|
30
|
+
if (override) {
|
|
31
|
+
return {
|
|
32
|
+
dir: isAbsolute(override) ? override : resolve(opts.agentWorkdir, override),
|
|
33
|
+
scope: 'project',
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return { dir: join(opts.daemonHome, '.pi', 'agent'), scope: 'home' }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Install our bundle without replacing an operator's existing Pi extensions. */
|
|
40
|
+
export function installPiExtension(opts: {
|
|
41
|
+
agentDir: string
|
|
42
|
+
bundlePath: string
|
|
43
|
+
/** Project dirs belong to the workspace, so we may create them. ~/.pi is the
|
|
44
|
+
* operator's: install into it only if they already use pi. */
|
|
45
|
+
createMissing?: boolean
|
|
46
|
+
}): InstallPiExtensionResult {
|
|
47
|
+
if (!opts.createMissing && !existsSync(opts.agentDir)) {
|
|
48
|
+
return { status: 'skipped', reason: 'no Pi home' }
|
|
49
|
+
}
|
|
50
|
+
const target = join(opts.agentDir, 'extensions', 'zooid-tasks.js')
|
|
51
|
+
mkdirSync(dirname(target), { recursive: true })
|
|
52
|
+
const source = readFileSync(opts.bundlePath)
|
|
53
|
+
if (existsSync(target) && readFileSync(target).equals(source)) return { status: 'unchanged', target }
|
|
54
|
+
writeFileSync(target, source)
|
|
55
|
+
return { status: 'installed', target }
|
|
56
|
+
}
|