@openchambery/web 1.19.21-beta.1 → 2.0.0-beta.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 +13 -11
- package/bin/cli-opencode.test.js +208 -0
- package/bin/cli.js +62 -9
- package/bin/lib/cli-startup.js +105 -2
- package/bin/lib/cli-startup.test.js +165 -0
- package/dist/assets/{AgentAvatar-NT957MuI.js → AgentAvatar-CLWWNu_Q.js} +1 -1
- package/dist/assets/AssistantView-BTCkm8yk.js +3 -0
- package/dist/assets/{DiagramView-Bh06xinl.js → DiagramView-xuSJTnv7.js} +1 -1
- package/dist/assets/{FadeInOnReveal-CilRl4gc.js → FadeInOnReveal-Ov0D96d0.js} +1 -1
- package/dist/assets/{Icon-i5GiQRLq.js → Icon-DD-BuMfZ.js} +1 -1
- package/dist/assets/MarkdownRenderer-bc_p1H7l.js +2 -0
- package/dist/assets/{MarkdownRendererImpl-f2agCc4q.js → MarkdownRendererImpl-SKi4oG0c.js} +1 -1
- package/dist/assets/{MarkstreamRendererImpl-ChD4WD2v.js → MarkstreamRendererImpl-CnkodGJW.js} +1 -1
- package/dist/assets/MobileDetailNavigation-Bnx59U_J.js +1 -0
- package/dist/assets/{MobileShareBridge-D7SG0ueZ.js → MobileShareBridge-BQlP4J-F.js} +1 -1
- package/dist/assets/MobileSurface-BXLeiZ4d.js +2 -0
- package/dist/assets/{MultiRunWindow-CjCw1X4n.js → MultiRunWindow-ChZGob0v.js} +1 -1
- package/dist/assets/{OnboardingScreen-BGRLk4Wi.js → OnboardingScreen-DtQJxZG-.js} +1 -1
- package/dist/assets/{OverlayScrollbar-NuQI58XD.js → OverlayScrollbar-pMwxaCca.js} +1 -1
- package/dist/assets/SettingsView-B5I0KDTZ.js +25 -0
- package/dist/assets/{SettingsWindow-C2DgbXJ3.js → SettingsWindow-DfnsFa8y.js} +1 -1
- package/dist/assets/{TerminalView-lubDPKMs.js → TerminalView-Dh9MWCpS.js} +1 -1
- package/dist/assets/{ToolOutputDialog-CzgW3-Cb.js → ToolOutputDialog-BejmjrRk.js} +1 -1
- package/dist/assets/{appThemeRegistry-BKc-qXbQ.js → appThemeRegistry-COGfxTFV.js} +1 -1
- package/dist/assets/{button-DtzFDvij.js → button-D-rATN7w.js} +1 -1
- package/dist/assets/{collapsible-D-nzhcyF.js → collapsible-BXRd5_Hr.js} +1 -1
- package/dist/assets/{context-menu-BzVSzHLG.js → context-menu-jGtH6fR9.js} +1 -1
- package/dist/assets/{diagram-2YWalSb5.js → diagram-DQf7Y_uR.js} +1 -1
- package/dist/assets/{dialog-DGV7DsZC.js → dialog-bfbvR4VH.js} +1 -1
- package/dist/assets/es-c52LTHHe.js +15 -0
- package/dist/assets/{fileMentionTouchSelection-BTkP7aYI.js → fileMentionTouchSelection-BvrNCroG.js} +1 -1
- package/dist/assets/{fr-DsBZeN8Y.js → fr-PisFbUE8.js} +3 -3
- package/dist/assets/gitApi-ButwzQ0N.js +9 -0
- package/dist/assets/{input-CbB2HdLg.js → input-8r6F_Fza.js} +1 -1
- package/dist/assets/insertionBoundaries-DGs7S5zv.js +1 -0
- package/dist/assets/ja-C8Ikun3Z.js +15 -0
- package/dist/assets/ko-ClFys5o2.js +15 -0
- package/dist/assets/main-CCE_4y5F.js +2 -0
- package/dist/assets/main-Dn9rpsgl.js +169 -0
- package/dist/assets/{markdownHeightCache-C9ym9Tsb.js → markdownHeightCache-1Qo6y6IJ.js} +1 -1
- package/dist/assets/miniChat-BpjxVqgg.js +2 -0
- package/dist/assets/mobile-nMJCaNq1.js +2 -0
- package/dist/assets/multirun-BvSG94mW.js +4 -0
- package/dist/assets/pl-CnaKWN5F.js +15 -0
- package/dist/assets/platform-CWTIp02q.js +4 -0
- package/dist/assets/projectMeta-DOe49dM_.js +3 -0
- package/dist/assets/pt-BR-s8OpfRI6.js +15 -0
- package/dist/assets/renderElectronMiniChatApp-R6dKh79f.js +2 -0
- package/dist/assets/renderMobileApp-y-S8y8v_.js +28 -0
- package/dist/assets/{runtimeConfig-PpnZiwcW.js → runtimeConfig-BMvqa5we.js} +1 -1
- package/dist/assets/{runtimeEndpointReset-BGjzNuQl.js → runtimeEndpointReset-B6BxhvR0.js} +6 -6
- package/dist/assets/sessionChangeSummary-VVBlEXuh.js +2 -0
- package/dist/assets/{sessionLookup-CbbzalcH.js → sessionLookup-gh-hVRIc.js} +1 -1
- package/dist/assets/{sortable-tabs-strip-CfgEJfB0.js → sortable-tabs-strip-CudoSgV4.js} +1 -1
- package/dist/assets/src-BzX5UI-c.css +2 -0
- package/dist/assets/{store-B6dImdlY.js → store-DJczmczv.js} +4 -4
- package/dist/assets/{terminalApi-xjqssKke.js → terminalApi-DiF6JmBP.js} +1 -1
- package/dist/assets/textarea-3XR8sUfy.js +1 -0
- package/dist/assets/{tooltip-Djn7MSOX.js → tooltip-CQvpK-UV.js} +1 -1
- package/dist/assets/uk-CaX0iqkB.js +15 -0
- package/dist/assets/{useAppFontEffects-BJBcy-84.js → useAppFontEffects-Cpmpo7Wb.js} +45 -45
- package/dist/assets/useDesktopWindowControlsLayout-B1GX59-L.js +1 -0
- package/dist/assets/{useEffectiveDirectory-CzHynoi_.js → useEffectiveDirectory-CN6JoCFw.js} +1 -1
- package/dist/assets/{useFontPreferences-B1JYyzpK.js → useFontPreferences-DcbXQOkc.js} +1 -1
- package/dist/assets/useMobileNavigationStore-BVjFtXSy.js +414 -0
- package/dist/assets/{useSessionAutoCleanup-DzV9N6G-.js → useSessionAutoCleanup-BLjymaFt.js} +1 -1
- package/dist/assets/{useWorkerHighlightedLines-Bi9ASKr_.js → useWorkerHighlightedLines-Bqn4AiBL.js} +1 -1
- package/dist/assets/vendor-opencode-client-BOe2qpQb.js +12 -0
- package/dist/assets/{vendor-yaml-DIcAK3EC.js → vendor-yaml-C9KlJAlj.js} +37 -37
- package/dist/assets/zh-CN-20MYEjha.js +15 -0
- package/dist/assets/{zh-TW-BsOQbrwT.js → zh-TW-DiN04qTw.js} +3 -3
- package/dist/index.html +6 -6
- package/dist/mini-chat.html +6 -6
- package/dist/mobile.html +6 -6
- package/package.json +2 -2
- package/server/index.js +107 -0
- package/server/lib/assistants/DOCUMENTATION.md +18 -18
- package/server/lib/assistants/assign.js +2 -1
- package/server/lib/assistants/contact-store.js +37 -19
- package/server/lib/assistants/projection-history.test.js +207 -0
- package/server/lib/assistants/routes.js +5 -5
- package/server/lib/assistants/service.js +493 -123
- package/server/lib/assistants/service.test.js +203 -133
- package/server/lib/conversations/DOCUMENTATION.md +4 -4
- package/server/lib/conversations/service.js +86 -57
- package/server/lib/conversations/service.test.js +116 -100
- package/server/lib/event-stream/global-hub.js +2 -1
- package/server/lib/llm/DOCUMENTATION.md +71 -84
- package/server/lib/llm/catalog.js +111 -45
- package/server/lib/llm/catalog.test.js +121 -59
- package/server/lib/llm/completions.js +37 -12
- package/server/lib/llm/completions.test.js +45 -4
- package/server/lib/llm/generate.js +421 -450
- package/server/lib/llm/generate.test.js +553 -487
- package/server/lib/llm/routes.js +6 -4
- package/server/lib/message-queue/DOCUMENTATION.md +5 -5
- package/server/lib/message-queue/opencode-adapter.js +191 -104
- package/server/lib/message-queue/opencode-adapter.test.js +328 -58
- package/server/lib/message-queue/runtime.test.js +6 -6
- package/server/lib/message-queue/worker.js +7 -1
- package/server/lib/opencode/DOCUMENTATION.md +28 -5
- package/server/lib/opencode/config-entity-routes.js +84 -13
- package/server/lib/opencode/config-entity-routes.test.js +41 -10
- package/server/lib/opencode/ensure-cli.js +239 -0
- package/server/lib/opencode/ensure-cli.test.js +119 -0
- package/server/lib/opencode/env-runtime.js +193 -110
- package/server/lib/opencode/env-runtime.test.js +221 -17
- package/server/lib/opencode/feature-routes-runtime.js +37 -1
- package/server/lib/opencode/lifecycle.js +204 -70
- package/server/lib/opencode/lifecycle.test.js +376 -6
- package/server/lib/opencode/network-runtime.js +28 -16
- package/server/lib/opencode/network-runtime.test.js +68 -4
- package/server/lib/opencode/opencode2-pin.js +139 -0
- package/server/lib/opencode/opencode2-pin.test.js +87 -0
- package/server/lib/opencode/opencode2-sidecar.e2e.test.js +203 -0
- package/server/lib/opencode/plugin-compatibility.js +15 -0
- package/server/lib/opencode/plugin-compatibility.test.js +21 -0
- package/server/lib/opencode/plugins.js +4 -3
- package/server/lib/opencode/plugins.test.js +12 -0
- package/server/lib/opencode/proxy.js +153 -16
- package/server/lib/opencode/proxy.test.js +120 -0
- package/server/lib/opencode/routes.js +25 -32
- package/server/lib/opencode/routes.test.js +51 -52
- package/server/lib/opencode/server-utils-runtime.js +2 -0
- package/server/lib/opencode/skill-routes.js +6 -7
- package/server/lib/opencode/skill-routes.test.js +36 -5
- package/server/lib/opencode/v1-migration-gate.js +157 -0
- package/server/lib/opencode/v1-migration-gate.test.js +111 -0
- package/server/lib/opencode/v2-client.js +49 -0
- package/server/lib/opencode/watcher.js +2 -1
- package/server/lib/opencode/watcher.test.js +1 -1
- package/server/lib/scheduled-tasks/DOCUMENTATION.md +71 -39
- package/server/lib/scheduled-tasks/managed-tool-route.js +31 -1
- package/server/lib/scheduled-tasks/managed-tool-route.test.js +23 -0
- package/server/lib/scheduled-tasks/routes.js +27 -0
- package/server/lib/scheduled-tasks/routes.test.js +94 -0
- package/server/lib/scheduled-tasks/runtime.js +331 -308
- package/server/lib/scheduled-tasks/runtime.test.js +530 -318
- package/server/lib/session-goal/DOCUMENTATION.md +65 -14
- package/server/lib/session-goal/capability.js +57 -0
- package/server/lib/session-goal/capability.test.js +33 -0
- package/server/lib/session-goal/routes.js +231 -2
- package/server/lib/session-goal/routes.test.js +211 -0
- package/server/lib/session-goal/runtime.js +46 -4
- package/server/lib/session-goal/runtime.test.js +62 -1
- package/server/lib/session-index/sync-runtime.js +20 -17
- package/server/lib/session-index/sync-runtime.test.js +9 -8
- package/server/lib/session-metadata/DOCUMENTATION.md +41 -0
- package/server/lib/session-metadata/routes.js +94 -0
- package/server/lib/session-metadata/routes.test.js +111 -0
- package/server/lib/session-metadata/session-metadata-store.js +235 -0
- package/server/lib/session-metadata/session-metadata-store.test.js +184 -0
- package/server/lib/session-turn-pages/DOCUMENTATION.md +3 -3
- package/server/lib/session-turn-pages/reconcile.service.js +1 -1
- package/server/lib/session-turn-pages/reconcile.service.test.js +16 -0
- package/server/lib/session-turn-pages/routes.js +204 -71
- package/server/lib/session-turn-pages/routes.test.js +285 -0
- package/server/lib/session-turn-pages/service.js +6 -2
- package/server/lib/session-turn-pages/service.test.js +34 -0
- package/server/lib/small-model/DOCUMENTATION.md +5 -4
- package/server/lib/small-model/catalog.js +56 -6
- package/server/lib/small-model/catalog.test.js +47 -0
- package/server/lib/small-model/index.js +3 -3
- package/server/lib/small-model/opencode-session.js +50 -206
- package/server/lib/small-model/opencode-session.test.js +58 -88
- package/server/opencode-proxy.test.js +61 -12
- package/dist/assets/AssistantView-BtGYjSW5.js +0 -3
- package/dist/assets/MarkdownRenderer-AwDKOCvD.js +0 -2
- package/dist/assets/MobileDetailNavigation-B6fGRYsg.js +0 -1
- package/dist/assets/MobileSurface-BY7eErHN.js +0 -2
- package/dist/assets/SettingsView-lcRi35Y3.js +0 -25
- package/dist/assets/es-rqMiRP7-.js +0 -15
- package/dist/assets/gitApi-CcIuekQ3.js +0 -7
- package/dist/assets/insertionBoundaries-BocNNP9Q.js +0 -1
- package/dist/assets/ja-Bgr8-dOg.js +0 -15
- package/dist/assets/ko-B_Gxh-0l.js +0 -15
- package/dist/assets/main-CFLmpNC5.js +0 -169
- package/dist/assets/main-Ckj_IpUy.js +0 -2
- package/dist/assets/miniChat-Dq1CTKNs.js +0 -2
- package/dist/assets/mobile-DlJ0Yr7h.js +0 -2
- package/dist/assets/multirun-BGUKIJys.js +0 -4
- package/dist/assets/pl-DW2XJGC4.js +0 -15
- package/dist/assets/platform-0w_Q9_ji.js +0 -2
- package/dist/assets/projectMeta-Bft2t6GF.js +0 -3
- package/dist/assets/pt-BR-CIsanf4T.js +0 -15
- package/dist/assets/renderElectronMiniChatApp-CTbXbB0Y.js +0 -2
- package/dist/assets/renderMobileApp-DLewUqoE.js +0 -28
- package/dist/assets/sessionChangeSummary-DiqwX3vZ.js +0 -2
- package/dist/assets/src-rS3zCcsC.css +0 -2
- package/dist/assets/textarea-DpK2Z0Gp.js +0 -1
- package/dist/assets/uk-BPmPEUYJ.js +0 -15
- package/dist/assets/useDesktopWindowControlsLayout-3Bm0rXCQ.js +0 -1
- package/dist/assets/useMobileNavigationStore-BIyCYi_z.js +0 -413
- package/dist/assets/vendor-opencode-sdk-C07HQypa.js +0 -7
- package/dist/assets/zh-CN-R8-mDcIp.js +0 -15
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getSessionGoalCapability,
|
|
3
|
+
isSessionGoalSupported,
|
|
4
|
+
sessionGoalUnavailableMessage,
|
|
5
|
+
} from '../session-goal/capability.js';
|
|
1
6
|
import { MANAGED_SCHEDULED_TASK_TOOL_PATH } from './managed-tool-contract.js';
|
|
2
7
|
|
|
3
8
|
const MAX_ID_LENGTH = 512;
|
|
@@ -263,6 +268,17 @@ export const registerScheduledTaskToolRoute = (app, dependencies) => {
|
|
|
263
268
|
: new Set(['taskId', 'name', 'enabled', 'schedule', 'execution']), 'input');
|
|
264
269
|
validateTaskInputFields(input);
|
|
265
270
|
|
|
271
|
+
const refuseGoalExecution = (execution) => {
|
|
272
|
+
if (execution?.goalEnabled !== true || isSessionGoalSupported()) {
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
const capability = getSessionGoalCapability();
|
|
276
|
+
const error = new Error(sessionGoalUnavailableMessage(capability));
|
|
277
|
+
error.statusCode = 501;
|
|
278
|
+
error.capability = capability;
|
|
279
|
+
return error;
|
|
280
|
+
};
|
|
281
|
+
|
|
266
282
|
if (operation === 'update') {
|
|
267
283
|
const patch = {
|
|
268
284
|
...(input.name === undefined ? {} : { name: input.name }),
|
|
@@ -270,6 +286,8 @@ export const registerScheduledTaskToolRoute = (app, dependencies) => {
|
|
|
270
286
|
...(input.schedule === undefined ? {} : { schedule: input.schedule }),
|
|
271
287
|
...(input.execution === undefined ? {} : { execution: input.execution }),
|
|
272
288
|
};
|
|
289
|
+
const goalRefusal = refuseGoalExecution(patch.execution);
|
|
290
|
+
if (goalRefusal) throw goalRefusal;
|
|
273
291
|
const patched = await projectConfigRuntime.patchScheduledTask(project.id, taskID, patch);
|
|
274
292
|
if (!patched?.task) return res.status(404).json({ error: 'Schedule not found' });
|
|
275
293
|
const schedulerSynced = await syncAfterMutation(project.id, operation);
|
|
@@ -285,6 +303,8 @@ export const registerScheduledTaskToolRoute = (app, dependencies) => {
|
|
|
285
303
|
if (operation === 'create' && (!execution.providerID || !execution.modelID)) {
|
|
286
304
|
throw new Error('execution.providerID and execution.modelID are required from the user message or input');
|
|
287
305
|
}
|
|
306
|
+
const goalRefusal = refuseGoalExecution(execution);
|
|
307
|
+
if (goalRefusal) throw goalRefusal;
|
|
288
308
|
const taskInput = {
|
|
289
309
|
...(input.name === undefined ? {} : { name: input.name }),
|
|
290
310
|
...(input.enabled === undefined ? {} : { enabled: input.enabled }),
|
|
@@ -296,7 +316,17 @@ export const registerScheduledTaskToolRoute = (app, dependencies) => {
|
|
|
296
316
|
return res.status(201).json({ projectId: project.id, created: upserted.created, task: upserted.task, tasks: upserted.tasks, schedulerSynced });
|
|
297
317
|
} catch (error) {
|
|
298
318
|
const statusCode = error?.statusCode || (isValidationError(error?.message || '') ? 400 : 500);
|
|
299
|
-
if (statusCode >= 500
|
|
319
|
+
if (statusCode >= 500 && statusCode !== 501) {
|
|
320
|
+
logger.error?.('[ScheduledTaskTool] request failed', { operation: req.body?.operation, statusCode });
|
|
321
|
+
}
|
|
322
|
+
if (statusCode === 501) {
|
|
323
|
+
const capability = error?.capability || getSessionGoalCapability();
|
|
324
|
+
return res.status(501).json({
|
|
325
|
+
error: error?.message || sessionGoalUnavailableMessage(capability),
|
|
326
|
+
reason: capability.reason,
|
|
327
|
+
capability,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
300
330
|
return res.status(statusCode).json({ error: statusCode >= 500 ? 'Failed to manage schedule' : (error?.message || 'Invalid schedule request') });
|
|
301
331
|
}
|
|
302
332
|
});
|
|
@@ -265,4 +265,27 @@ describe('managed scheduled task tool route', () => {
|
|
|
265
265
|
expect(oversized.status).toBe(413);
|
|
266
266
|
} finally { fixture.restore(); }
|
|
267
267
|
});
|
|
268
|
+
|
|
269
|
+
it('allows create/update with goalEnabled when Host goal state is supported', async () => {
|
|
270
|
+
const fixture = createApp();
|
|
271
|
+
try {
|
|
272
|
+
const created = await request(fixture.app).post(MANAGED_SCHEDULED_TASK_TOOL_PATH).send(body('create', {
|
|
273
|
+
name: 'Goal task',
|
|
274
|
+
schedule: { kind: 'daily', time: '10:00', timezone: 'UTC' },
|
|
275
|
+
execution: { prompt: 'review', goalEnabled: true },
|
|
276
|
+
}));
|
|
277
|
+
expect(created.status).toBe(201);
|
|
278
|
+
expect(fixture.projectConfigRuntime.upsertScheduledTask).toHaveBeenCalled();
|
|
279
|
+
expect(fixture.projectConfigRuntime.upsertScheduledTask.mock.calls[0][1]).toMatchObject({
|
|
280
|
+
execution: expect.objectContaining({ goalEnabled: true }),
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
const updated = await request(fixture.app).post(MANAGED_SCHEDULED_TASK_TOOL_PATH).send(body('update', {
|
|
284
|
+
taskId: 'task_1',
|
|
285
|
+
execution: { goalEnabled: true },
|
|
286
|
+
}));
|
|
287
|
+
expect(updated.status).toBe(200);
|
|
288
|
+
expect(fixture.projectConfigRuntime.patchScheduledTask).toHaveBeenCalled();
|
|
289
|
+
} finally { fixture.restore(); }
|
|
290
|
+
});
|
|
268
291
|
});
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getSessionGoalCapability,
|
|
3
|
+
isSessionGoalSupported,
|
|
4
|
+
sessionGoalUnavailableMessage,
|
|
5
|
+
} from '../session-goal/capability.js';
|
|
6
|
+
|
|
1
7
|
const asNonEmptyString = (value) => {
|
|
2
8
|
if (typeof value !== 'string') {
|
|
3
9
|
return null;
|
|
@@ -6,6 +12,22 @@ const asNonEmptyString = (value) => {
|
|
|
6
12
|
return trimmed.length > 0 ? trimmed : null;
|
|
7
13
|
};
|
|
8
14
|
|
|
15
|
+
/** Reject create/edit that enables goal when Host goal state is unavailable. */
|
|
16
|
+
const rejectUnsupportedGoalExecution = (taskInput) => {
|
|
17
|
+
if (taskInput?.execution?.goalEnabled !== true) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
if (isSessionGoalSupported()) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const capability = getSessionGoalCapability();
|
|
24
|
+
return {
|
|
25
|
+
error: sessionGoalUnavailableMessage(capability),
|
|
26
|
+
reason: capability.reason,
|
|
27
|
+
capability,
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
9
31
|
const parseProjectID = (req) => asNonEmptyString(req?.params?.projectId);
|
|
10
32
|
const parseTaskID = (req) => asNonEmptyString(req?.params?.taskId);
|
|
11
33
|
|
|
@@ -182,6 +204,11 @@ export const registerScheduledTaskRoutes = (app, dependencies) => {
|
|
|
182
204
|
return res.status(404).json({ error: 'Project not found' });
|
|
183
205
|
}
|
|
184
206
|
|
|
207
|
+
const goalRefusal = rejectUnsupportedGoalExecution(taskInput);
|
|
208
|
+
if (goalRefusal) {
|
|
209
|
+
return res.status(501).json(goalRefusal);
|
|
210
|
+
}
|
|
211
|
+
|
|
185
212
|
const upserted = await projectConfigRuntime.upsertScheduledTask(projectID, taskInput);
|
|
186
213
|
const schedulerSynced = await syncAfterMutation(projectID);
|
|
187
214
|
|
|
@@ -359,4 +359,98 @@ describe('scheduled task mutation routes', () => {
|
|
|
359
359
|
await Promise.resolve();
|
|
360
360
|
expect(scheduledTasksRuntime.syncProject).toHaveBeenCalledTimes(4);
|
|
361
361
|
});
|
|
362
|
+
|
|
363
|
+
it('allows create/edit with goalEnabled when Host goal state is supported', async () => {
|
|
364
|
+
const savedTask = {
|
|
365
|
+
id: 'goal-task',
|
|
366
|
+
name: 'Goal task',
|
|
367
|
+
execution: { prompt: 'do the work', goalEnabled: true },
|
|
368
|
+
};
|
|
369
|
+
const projectConfigRuntime = {
|
|
370
|
+
upsertScheduledTask: vi.fn(async () => ({ task: savedTask, tasks: [savedTask], created: true })),
|
|
371
|
+
deleteScheduledTask: vi.fn(),
|
|
372
|
+
listScheduledTasks: vi.fn(),
|
|
373
|
+
};
|
|
374
|
+
const routes = registerMutationRoutes({
|
|
375
|
+
projectConfigRuntime,
|
|
376
|
+
scheduledTasksRuntime: { syncProject: vi.fn(async () => {}) },
|
|
377
|
+
scheduleSyncRetry: vi.fn(),
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
const created = createResponse();
|
|
381
|
+
await routes.put({
|
|
382
|
+
params: { projectId: 'project-a' },
|
|
383
|
+
body: {
|
|
384
|
+
task: {
|
|
385
|
+
name: 'Goal task',
|
|
386
|
+
execution: {
|
|
387
|
+
prompt: 'do the work',
|
|
388
|
+
providerID: 'openai',
|
|
389
|
+
modelID: 'gpt',
|
|
390
|
+
goalEnabled: true,
|
|
391
|
+
},
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
}, created);
|
|
395
|
+
|
|
396
|
+
expect(created.statusCode).toBe(200);
|
|
397
|
+
expect(projectConfigRuntime.upsertScheduledTask).toHaveBeenCalledTimes(1);
|
|
398
|
+
expect(projectConfigRuntime.upsertScheduledTask.mock.calls[0][1]).toMatchObject({
|
|
399
|
+
execution: expect.objectContaining({ goalEnabled: true }),
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
const updatedTask = { ...savedTask, id: 'existing', name: 'Existing' };
|
|
403
|
+
projectConfigRuntime.upsertScheduledTask.mockResolvedValueOnce({
|
|
404
|
+
task: updatedTask,
|
|
405
|
+
tasks: [updatedTask],
|
|
406
|
+
created: false,
|
|
407
|
+
});
|
|
408
|
+
const updated = createResponse();
|
|
409
|
+
await routes.put({
|
|
410
|
+
params: { projectId: 'project-a' },
|
|
411
|
+
body: {
|
|
412
|
+
task: {
|
|
413
|
+
id: 'existing',
|
|
414
|
+
name: 'Existing',
|
|
415
|
+
execution: {
|
|
416
|
+
prompt: 'do the work',
|
|
417
|
+
providerID: 'openai',
|
|
418
|
+
modelID: 'gpt',
|
|
419
|
+
goalEnabled: true,
|
|
420
|
+
},
|
|
421
|
+
},
|
|
422
|
+
},
|
|
423
|
+
}, updated);
|
|
424
|
+
|
|
425
|
+
expect(updated.statusCode).toBe(200);
|
|
426
|
+
expect(projectConfigRuntime.upsertScheduledTask).toHaveBeenCalledTimes(2);
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
it('allows ordinary non-goal task create when goal is unsupported', async () => {
|
|
430
|
+
const savedTask = { id: 'plain', name: 'Plain' };
|
|
431
|
+
const projectConfigRuntime = {
|
|
432
|
+
upsertScheduledTask: vi.fn(async () => ({ task: savedTask, tasks: [savedTask], created: true })),
|
|
433
|
+
deleteScheduledTask: vi.fn(),
|
|
434
|
+
listScheduledTasks: vi.fn(),
|
|
435
|
+
};
|
|
436
|
+
const routes = registerMutationRoutes({
|
|
437
|
+
projectConfigRuntime,
|
|
438
|
+
scheduledTasksRuntime: { syncProject: vi.fn(async () => {}) },
|
|
439
|
+
scheduleSyncRetry: vi.fn(),
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
const response = createResponse();
|
|
443
|
+
await routes.put({
|
|
444
|
+
params: { projectId: 'project-a' },
|
|
445
|
+
body: {
|
|
446
|
+
task: {
|
|
447
|
+
name: 'Plain',
|
|
448
|
+
execution: { prompt: 'hello', providerID: 'openai', modelID: 'gpt' },
|
|
449
|
+
},
|
|
450
|
+
},
|
|
451
|
+
}, response);
|
|
452
|
+
|
|
453
|
+
expect(response.statusCode).toBe(200);
|
|
454
|
+
expect(projectConfigRuntime.upsertScheduledTask).toHaveBeenCalledTimes(1);
|
|
455
|
+
});
|
|
362
456
|
});
|