import assert from 'node:assert/strict'; import test from 'node:test'; import { attachPortalGoalRunRoutes } from './portal-goal-run-routes.mjs'; function createRouterRecorder() { const routes = new Map(); return { routes, get(path, handler) { routes.set(`GET ${path}`, handler); }, post(path, handler) { routes.set(`POST ${path}`, handler); }, delete(path, handler) { routes.set(`DELETE ${path}`, handler); }, }; } function createResponseRecorder() { return { statusCode: 200, body: undefined, status(code) { this.statusCode = code; return this; }, json(body) { this.body = body; return this; }, }; } function createRequest(overrides = {}) { return { body: {}, query: {}, params: {}, currentUser: { id: 'user-canary' }, ...overrides, }; } function enabledGoalRunService(overrides = {}) { return { async createGoalRun(input) { return { id: 'goal-1', title: input.title, intentSummary: input.intentSummary, checkpoints: [{ id: 'cp-1', title: '启动', status: 'pending' }], currentCheckpointId: 'cp-1', }; }, async listGoalRuns() { return [{ id: 'goal-1', title: '长期任务', status: 'active' }]; }, async getGoalRun({ goalRunId }) { if (goalRunId !== 'goal-1') return null; return { id: 'goal-1', title: '长期任务', checkpoints: [{ id: 'cp-1', title: '启动', status: 'running' }], }; }, async approveCheckpoint() { return { id: 'goal-1', checkpoints: [{ id: 'cp-1', status: 'approved' }] }; }, async pauseGoal() { return { id: 'goal-1', status: 'paused' }; }, async resumeGoal() { return { goal: { id: 'goal-1', status: 'active' }, checkpointId: 'cp-2' }; }, async cancelGoal() { return { id: 'goal-1', status: 'cancelled' }; }, ...overrides, }; } const enabledEnv = { GOAL_RUN_ENABLED: '1', GOAL_RUN_CANARY_USER_IDS: 'user-canary', }; test('Goal Run routes preserve MVP inventory', () => { const api = createRouterRecorder(); attachPortalGoalRunRoutes(api, { getGoalRunService: () => enabledGoalRunService(), env: enabledEnv, }); assert.deepEqual([...api.routes.keys()], [ 'POST /goals', 'GET /goals', 'GET /goals/:goalRunId', 'POST /goals/:goalRunId/checkpoints/:checkpointId/approve', 'POST /goals/:goalRunId/pause', 'POST /goals/:goalRunId/resume', 'DELETE /goals/:goalRunId', ]); }); test('POST /goals returns 503 when service unavailable', async () => { const api = createRouterRecorder(); attachPortalGoalRunRoutes(api, { getGoalRunService: () => null, env: enabledEnv, }); const res = createResponseRecorder(); await api.routes.get('POST /goals')( createRequest({ body: { title: '任务', intentSummary: '分阶段完成' }, }), res, ); assert.equal(res.statusCode, 503); }); test('POST /goals creates goal for enabled canary user', async () => { const api = createRouterRecorder(); attachPortalGoalRunRoutes(api, { getGoalRunService: () => enabledGoalRunService(), env: enabledEnv, }); const res = createResponseRecorder(); await api.routes.get('POST /goals')( createRequest({ body: { title: '准备下季度产品规划', intentSummary: '收集竞品并输出草案', }, }), res, ); assert.equal(res.statusCode, 201); assert.equal(res.body.goal.id, 'goal-1'); }); test('GET /goals rejects non-canary user', async () => { const api = createRouterRecorder(); attachPortalGoalRunRoutes(api, { getGoalRunService: () => enabledGoalRunService(), env: enabledEnv, }); const res = createResponseRecorder(); await api.routes.get('GET /goals')( createRequest({ currentUser: { id: 'other-user' } }), res, ); assert.equal(res.statusCode, 403); }); test('POST /goals/:id/resume returns checkpoint binding hint', async () => { const api = createRouterRecorder(); attachPortalGoalRunRoutes(api, { getGoalRunService: () => enabledGoalRunService(), env: enabledEnv, }); const res = createResponseRecorder(); await api.routes.get('POST /goals/:goalRunId/resume')( createRequest({ params: { goalRunId: 'goal-1' } }), res, ); assert.equal(res.statusCode, 200); assert.equal(res.body.checkpointId, 'cp-2'); }); test('POST approve auto-dispatches agent run when session_id provided', async () => { const createdRuns = []; const api = createRouterRecorder(); attachPortalGoalRunRoutes(api, { getGoalRunService: () => enabledGoalRunService({ async getGoalRun({ goalRunId }) { if (goalRunId !== 'goal-1') return null; return { id: 'goal-1', title: '长期任务', checkpoints: [ { id: 'cp-1', title: '启动', status: 'approved' }, { id: 'cp-2', title: '输出', status: 'pending' }, ], }; }, async startNextCheckpoint({ goalRunId }) { return { goalRunId, checkpointId: 'cp-2' }; }, async approveCheckpoint() { return { id: 'goal-1', status: 'active', checkpoints: [{ id: 'cp-1', status: 'approved' }], }; }, }), getAgentRunGateway: () => ({ async createRun(userId, payload) { createdRuns.push({ userId, payload }); return { id: 'run-1', userId, sessionId: payload.sessionId, requestId: payload.requestId, status: 'queued', }; }, }), env: enabledEnv, }); const res = createResponseRecorder(); await api.routes.get('POST /goals/:goalRunId/checkpoints/:checkpointId/approve')( createRequest({ params: { goalRunId: 'goal-1', checkpointId: 'cp-1' }, body: { session_id: 'session-1', feedback: '继续' }, }), res, ); assert.equal(res.statusCode, 200); assert.equal(res.body.goal.id, 'goal-1'); assert.equal(res.body.run.id, 'run-1'); assert.equal(createdRuns.length, 1); assert.equal(createdRuns[0].payload.sessionId, 'session-1'); assert.equal(createdRuns[0].payload.goalRunId, 'goal-1'); });