Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions apps/server/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,13 +3,13 @@
"version": "0.1.0",
"type": "module",
"scripts": {
"build": "tsdown",
"build": "nitro build",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2Build bypasses mandated tsdown configuration

Changing this package to invoke nitro build directly bypasses its tsdown.config.ts and the shared tsdown configuration required by the repository, leaving the server outside the standardized package build toolchain.

Context Used: CLAUDE.md (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/server/package.json
Line: 6
Comment:
**Build bypasses mandated tsdown configuration**
Changing this package to invoke `nitro build` directly bypasses its `tsdown.config.ts` and the shared tsdown configuration required by the repository, leaving the server outside the standardized package build toolchain.
**Context Used:** CLAUDE.md ([source](https://github.com/wolfstar-project/agent-zero/blob/main/CLAUDE.md))
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude CodeFix in CursorFix in Cursor Cloud Agents

"clean": "tsc -b --clean",
"dev": "TMPDIR=/tmp node --import tsx src/index.ts",
"lint": "oxlint --config ../../.oxlintrc.json --type-aware --type-check src",
"start": "node dist/index.js",
"dev": "nitro dev",
"lint": "oxlint --config ../../.oxlintrc.json --type-aware --type-check src server nitro.config.ts",
"start": "node .output/server/index.mjs",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1Documented server port is ignored

The new startup command launches Nitro without mapping the documented AGENT_ZERO_PORT variable to Nitro's port configuration. With AGENT_ZERO_PORT=4040, the built server refuses connections on 4040 and instead listens on port 3000. Configure startup to honor AGENT_ZERO_PORT, or update the documented configuration contract consistently, and add a listener regression test.

Artifacts

Nitro port runtime probe script

  • The authored executable starts the built server with a chosen environment variable and performs isolated real TCP port checks, proving which listener was created.

AGENT_ZERO_PORT startup output showing port 4040 refused

  • The executed AGENT_ZERO_PORT=4040 run shows 4040 refused, 3000 connected, and Nitro listening on 3000, confirming the documented variable is ignored.

NITRO_PORT startup output showing port 4040 connected

  • The executed NITRO_PORT=4040 control run shows 4040 connected, 3000 refused, and Nitro listening on 4040, confirming the runtime supports 4040 through its actual variable.

View artifacts

T-Rex Ran code and verified through T-Rex

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/server/package.json
Line: 10
Comment:
**Documented server port is ignored**
The new startup command launches Nitro without mapping the documented `AGENT_ZERO_PORT` variable to Nitro's port configuration. With `AGENT_ZERO_PORT=4040`, the built server refuses connections on 4040 and instead listens on port 3000. Configure startup to honor `AGENT_ZERO_PORT`, or update the documented configuration contract consistently, and add a listener regression test.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude CodeFix in CursorFix in Cursor Cloud Agents

"test": "vitest run src --passWithNoTests",
"typecheck": "tsc --project tsconfig.json --pretty false --noEmit"
"typecheck": "nitro prepare && tsc --project tsconfig.json --pretty false --noEmit"
},
"dependencies": {
"@agent-zero/agent": "workspace:*",
Expand All@@ -18,8 +18,7 @@
"@agent-zero/models": "workspace:*",
"@agent-zero/runner": "workspace:*",
"@agent-zero/shared": "workspace:*",
"@orpc/client": "^1.12.2",
"@orpc/server": "^1.12.2",
"nitro": "3.0.260522-beta",
"zod": "^4.1.5"
}
}
36 changes: 1 addition & 35 deletions apps/server/src/index.ts
Original file line numberDiff line numberDiff line change
@@ -1,35 +1 @@
import { createServer } from 'node:http';

import { onError } from '@orpc/server';
import { RPCHandler } from '@orpc/server/node';

import { router } from './router.js';

export const handler = new RPCHandler(router, {
interceptors: [onError((error) => console.error(error))],
});

export const server = createServer((request, response) => {
void handler
.handle(request, response, { context: {} })
.then(({ matched }) => {
if (!matched) {
response.statusCode = 404;
response.end('Not found');
}
return undefined;
})
.catch((error) => {
console.error(error);
response.statusCode = 500;
response.end('Internal server error');
return undefined;
});
});

if (import.meta.url === `file://${process.argv[1]}`) {
const port = Number(process.env.AGENT_ZERO_PORT ?? 4040);
server.listen(port, () =>
console.log(`Agent Zero oRPC API listening on http://localhost:${port}`),
);
}
export { createTask, getTask, health, listTasks, taskInput, tasks } from './router.js';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1Nitro routes are never registered

The entrypoint only re-exports task helpers and does not register Nitro handlers. A built and running server returns 404 Not Found for GET /health, GET /tasks, and GET /tasks/missing-task, so the control plane is unreachable over HTTP. Add configured Nitro route handlers for the health and task API contract and cover them with an HTTP-level test.

Artifacts

Nitro health and task endpoint validation script

  • Authored Bash script that builds the Nitro application, starts it, and captures HTTP responses for health and task control-plane requests, ending with the takeaway that it exercises the server rather than only unit helpers.

Nitro server control-plane responses before an attempted route fixture

  • Captured build and live HTTP output showing GET /health, GET /tasks, and GET /tasks/missing-task each return 404 Not Found, ending with the takeaway that the committed server exposes no control-plane routes.

Nitro server responses after an attempted conventional Nitro route fixture

  • Captured rebuild and live HTTP output after a temporary `apps/server/server/api` fixture, showing all three URLs still return 404 Not Found because this bare Nitro configuration does not discover that directory, ending with the takeaway that a correctly configured route registration is required.

View artifacts

T-Rex Ran code and verified through T-Rex

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/server/src/index.ts
Line: 1
Comment:
**Nitro routes are never registered**
The entrypoint only re-exports task helpers and does not register Nitro handlers. A built and running server returns `404 Not Found` for `GET /health`, `GET /tasks`, and `GET /tasks/missing-task`, so the control plane is unreachable over HTTP. Add configured Nitro route handlers for the health and task API contract and cover them with an HTTP-level test.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude CodeFix in CursorFix in Cursor Cloud Agents

26 changes: 18 additions & 8 deletions apps/server/src/router.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
import { call } from '@orpc/server';
import { describe, expect, it } from 'vitest';

import { router } from './router.js';
import { health, listTasks, taskInput } from './router.js';

describe('oRPC router', () => {
it('exposes a typed health procedure', async () => {
await expect(call(router.health, undefined)).resolves.toMatchObject({
status: 'ok',
service: 'agent-zero',
});
describe('server task API', () => {
it('exposes health metadata for Nitro handlers', () => {
expect(health()).toMatchObject({ status: 'ok', service: 'agent-zero' });
});

it('starts with an empty task collection', () => {
expect(listTasks()).toEqual({ tasks: [] });
});

it('keeps task input validation independent from HTTP transport', () => {
expect(
taskInput.parse({
repository: '.',
feedback: 'Check error handling',
mode: 'observe',
}),
).toMatchObject({ repository: '.', mode: 'observe' });
});
});
60 changes: 29 additions & 31 deletions apps/server/src/router.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,46 +3,44 @@ import { loadConfig } from '@agent-zero/config';
import { modelFromEnvironment } from '@agent-zero/models';
import { LocalRunner } from '@agent-zero/runner';
import type { TaskResult } from '@agent-zero/shared';
import { ORPCError, os } from '@orpc/server';
import { z } from 'zod';

export const tasks = new Map<string, TaskResult>();

const taskInput = z.object({
export const taskInput = z.object({
repository: z.string().min(1),
feedback: z.string().min(1),
mode: z.enum(['observe', 'suggest', 'fix', 'autonomous']),
source: z.string().optional(),
files: z.array(z.string()).optional(),
});

export const router = {
health: os.handler(() => ({ status: 'ok' as const, service: 'agent-zero', version: '0.1.0' })),
tasks: {
list: os.handler(() => ({ tasks: [...tasks.values()] })),
get: os.input(z.object({ id: z.string() })).handler(({ input }) => {
const task = tasks.get(input.id);
if (!task) throw new ORPCError('NOT_FOUND', { message: 'Task not found' });
return task;
}),
create: os.input(taskInput).handler(async ({ input }) => {
const config = await loadConfig(input.repository);
const agent = new AgentZero({
model: modelFromEnvironment(config.model.name, config.model.baseUrl),
runner: new LocalRunner(input.repository),
config,
});
const result = await agent.run({
repository: input.repository,
feedback: input.feedback,
mode: input.mode,
...(input.source ? { source: input.source } : {}),
...(input.files ? { files: input.files } : {}),
});
tasks.set(result.id, result);
return result;
}),
},
};
export function health() {
return { status: 'ok' as const, service: 'agent-zero', version: '0.1.0' };
}

export type AppRouter = typeof router;
export function listTasks() {
return { tasks: [...tasks.values()] };
}

export function getTask(id: string): TaskResult | undefined {
return tasks.get(id);
}

export async function createTask(input: z.infer<typeof taskInput>): Promise<TaskResult> {
const config = await loadConfig(input.repository);
const agent = new AgentZero({
model: modelFromEnvironment(config.model.name, config.model.baseUrl),
runner: new LocalRunner(input.repository),
config,
});
const result = await agent.run({
repository: input.repository,
feedback: input.feedback,
mode: input.mode,
...(input.source ? { source: input.source } : {}),
...(input.files ? { files: input.files } : {}),
});
tasks.set(result.id, result);
return result;
}
Loading