@jiggai/kitchen 0.3.1 → 0.3.3
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/.next/BUILD_ID +1 -1
- package/.next/build-manifest.json +2 -2
- package/.next/server/app/_global-error.html +2 -2
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +1 -1
- package/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/channels.html +2 -2
- package/.next/server/app/channels.rsc +1 -1
- package/.next/server/app/channels.segments/_full.segment.rsc +1 -1
- package/.next/server/app/channels.segments/_head.segment.rsc +1 -1
- package/.next/server/app/channels.segments/_index.segment.rsc +1 -1
- package/.next/server/app/channels.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/channels.segments/channels/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/channels.segments/channels.segment.rsc +1 -1
- package/.next/server/app/cron-jobs.html +1 -1
- package/.next/server/app/cron-jobs.rsc +1 -1
- package/.next/server/app/cron-jobs.segments/_full.segment.rsc +1 -1
- package/.next/server/app/cron-jobs.segments/_head.segment.rsc +1 -1
- package/.next/server/app/cron-jobs.segments/_index.segment.rsc +1 -1
- package/.next/server/app/cron-jobs.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/cron-jobs.segments/cron-jobs/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/cron-jobs.segments/cron-jobs.segment.rsc +1 -1
- package/.next/server/app/goals/new.html +2 -2
- package/.next/server/app/goals/new.rsc +1 -1
- package/.next/server/app/goals/new.segments/_full.segment.rsc +1 -1
- package/.next/server/app/goals/new.segments/_head.segment.rsc +1 -1
- package/.next/server/app/goals/new.segments/_index.segment.rsc +1 -1
- package/.next/server/app/goals/new.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/goals/new.segments/goals/new/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/goals/new.segments/goals/new.segment.rsc +1 -1
- package/.next/server/app/goals/new.segments/goals.segment.rsc +1 -1
- package/.next/server/app/goals.html +1 -1
- package/.next/server/app/goals.rsc +1 -1
- package/.next/server/app/goals.segments/_full.segment.rsc +1 -1
- package/.next/server/app/goals.segments/_head.segment.rsc +1 -1
- package/.next/server/app/goals.segments/_index.segment.rsc +1 -1
- package/.next/server/app/goals.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/goals.segments/goals/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/goals.segments/goals.segment.rsc +1 -1
- package/.next/server/app/settings.html +1 -1
- package/.next/server/app/settings.rsc +1 -1
- package/.next/server/app/settings.segments/_full.segment.rsc +1 -1
- package/.next/server/app/settings.segments/_head.segment.rsc +1 -1
- package/.next/server/app/settings.segments/_index.segment.rsc +1 -1
- package/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/settings.segments/settings.segment.rsc +1 -1
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +2 -2
- package/package.json +1 -2
- package/src/app/HomeClient.tsx +0 -207
- package/src/app/agents/[agentId]/agent-editor-tabs.tsx +0 -298
- package/src/app/agents/[agentId]/agent-editor.tsx +0 -468
- package/src/app/agents/[agentId]/page.tsx +0 -32
- package/src/app/api/__tests__/agents-add-route.test.ts +0 -143
- package/src/app/api/__tests__/agents-file-route.test.ts +0 -117
- package/src/app/api/__tests__/agents-files-route.test.ts +0 -61
- package/src/app/api/__tests__/agents-id-route.test.ts +0 -104
- package/src/app/api/__tests__/agents-identity-route.test.ts +0 -92
- package/src/app/api/__tests__/agents-route.test.ts +0 -54
- package/src/app/api/__tests__/agents-skills-install-route.test.ts +0 -131
- package/src/app/api/__tests__/agents-skills-route.test.ts +0 -64
- package/src/app/api/__tests__/agents-update-route.test.ts +0 -95
- package/src/app/api/__tests__/channels-bindings-route.test.ts +0 -143
- package/src/app/api/__tests__/cron-delete-route.test.ts +0 -93
- package/src/app/api/__tests__/cron-job-route.test.ts +0 -78
- package/src/app/api/__tests__/cron-jobs-route.test.ts +0 -116
- package/src/app/api/__tests__/cron-recipe-installed-route.test.ts +0 -114
- package/src/app/api/__tests__/gateway-restart-route.test.ts +0 -36
- package/src/app/api/__tests__/goals-promote-route.test.ts +0 -200
- package/src/app/api/__tests__/goals-route.test.ts +0 -184
- package/src/app/api/__tests__/ids-check-route.test.ts +0 -188
- package/src/app/api/__tests__/marketplace-recipes-route.test.ts +0 -123
- package/src/app/api/__tests__/recipes-clone-route.test.ts +0 -221
- package/src/app/api/__tests__/recipes-delete-route.test.ts +0 -248
- package/src/app/api/__tests__/recipes-id-route.test.ts +0 -166
- package/src/app/api/__tests__/recipes-route.test.ts +0 -57
- package/src/app/api/__tests__/recipes-team-agents-route.test.ts +0 -135
- package/src/app/api/__tests__/scaffold-route.test.ts +0 -173
- package/src/app/api/__tests__/settings-cron-installation-route.test.ts +0 -82
- package/src/app/api/__tests__/skills-available-route.test.ts +0 -47
- package/src/app/api/__tests__/swarms-start-route.test.ts +0 -79
- package/src/app/api/__tests__/swarms-status-route.test.ts +0 -42
- package/src/app/api/__tests__/teams-file-route.test.ts +0 -129
- package/src/app/api/__tests__/teams-files-route.test.ts +0 -57
- package/src/app/api/__tests__/teams-meta-route.test.ts +0 -113
- package/src/app/api/__tests__/teams-orchestrator-install-route.test.ts +0 -66
- package/src/app/api/__tests__/teams-orchestrator-route.test.ts +0 -59
- package/src/app/api/__tests__/teams-remove-team-route.test.ts +0 -122
- package/src/app/api/__tests__/teams-skills-install-route.test.ts +0 -78
- package/src/app/api/__tests__/teams-skills-route.test.ts +0 -73
- package/src/app/api/__tests__/teams-workflow-runs-route.test.ts +0 -85
- package/src/app/api/__tests__/teams-workflows-route.test.ts +0 -110
- package/src/app/api/__tests__/tickets-move-route.test.ts +0 -60
- package/src/app/api/agents/[id]/route.ts +0 -83
- package/src/app/api/agents/add/route.ts +0 -114
- package/src/app/api/agents/file/route.ts +0 -45
- package/src/app/api/agents/files/route.ts +0 -23
- package/src/app/api/agents/identity/route.ts +0 -41
- package/src/app/api/agents/route.ts +0 -22
- package/src/app/api/agents/skills/install/route.ts +0 -34
- package/src/app/api/agents/skills/route.ts +0 -39
- package/src/app/api/agents/update/route.ts +0 -52
- package/src/app/api/channels/bindings/route.ts +0 -63
- package/src/app/api/cron/__tests__/helpers.test.ts +0 -164
- package/src/app/api/cron/delete/route.ts +0 -23
- package/src/app/api/cron/helpers.ts +0 -172
- package/src/app/api/cron/job/route.ts +0 -22
- package/src/app/api/cron/jobs/route.ts +0 -52
- package/src/app/api/cron/recipe-installed/route.ts +0 -65
- package/src/app/api/gateway/restart/route.ts +0 -20
- package/src/app/api/goals/[id]/promote/route.ts +0 -119
- package/src/app/api/goals/[id]/route.ts +0 -54
- package/src/app/api/goals/route.ts +0 -44
- package/src/app/api/ids/check/route.ts +0 -113
- package/src/app/api/marketplace/recipes/[slug]/route.ts +0 -16
- package/src/app/api/marketplace/recipes/route.ts +0 -22
- package/src/app/api/recipes/[id]/route.ts +0 -62
- package/src/app/api/recipes/clone/route.ts +0 -106
- package/src/app/api/recipes/custom-team/route.ts +0 -193
- package/src/app/api/recipes/delete/helpers.ts +0 -65
- package/src/app/api/recipes/delete/route.ts +0 -73
- package/src/app/api/recipes/route.ts +0 -21
- package/src/app/api/recipes/team-agents/__tests__/helpers.test.ts +0 -156
- package/src/app/api/recipes/team-agents/helpers.ts +0 -151
- package/src/app/api/recipes/team-agents/route.ts +0 -80
- package/src/app/api/scaffold/__tests__/helpers.test.ts +0 -186
- package/src/app/api/scaffold/helpers.ts +0 -214
- package/src/app/api/scaffold/route.ts +0 -95
- package/src/app/api/settings/cron-installation/route.ts +0 -58
- package/src/app/api/skills/available/route.ts +0 -23
- package/src/app/api/swarms/start/route.ts +0 -100
- package/src/app/api/swarms/status/route.ts +0 -31
- package/src/app/api/teams/[teamId]/tickets/assign/route.ts +0 -105
- package/src/app/api/teams/[teamId]/tickets/assignees/route.ts +0 -27
- package/src/app/api/teams/[teamId]/tickets/delete/route.ts +0 -55
- package/src/app/api/teams/[teamId]/tickets/move/route.ts +0 -70
- package/src/app/api/teams/[teamId]/tickets/move-to-goals/route.ts +0 -56
- package/src/app/api/teams/file/route.ts +0 -46
- package/src/app/api/teams/files/route.ts +0 -63
- package/src/app/api/teams/memory/route.ts +0 -250
- package/src/app/api/teams/meta/route.ts +0 -43
- package/src/app/api/teams/orchestrator/install/route.ts +0 -129
- package/src/app/api/teams/orchestrator/route.ts +0 -216
- package/src/app/api/teams/remove-team/route.ts +0 -37
- package/src/app/api/teams/skills/install/route.ts +0 -18
- package/src/app/api/teams/skills/route.ts +0 -25
- package/src/app/api/teams/workflow-runs/route.ts +0 -534
- package/src/app/api/teams/workflow-templates/route.ts +0 -71
- package/src/app/api/teams/workflows/route.ts +0 -55
- package/src/app/api/tickets/assign/route.ts +0 -94
- package/src/app/api/tickets/assignees/route.ts +0 -24
- package/src/app/api/tickets/move/route.ts +0 -69
- package/src/app/channels/channels-client.tsx +0 -271
- package/src/app/channels/page.tsx +0 -5
- package/src/app/cron-jobs/cron-jobs-client.tsx +0 -243
- package/src/app/cron-jobs/page.tsx +0 -34
- package/src/app/favicon.ico +0 -0
- package/src/app/global-error.tsx +0 -50
- package/src/app/globals.css +0 -153
- package/src/app/goals/[id]/goal-editor.tsx +0 -162
- package/src/app/goals/[id]/page.tsx +0 -6
- package/src/app/goals/goals-client.tsx +0 -201
- package/src/app/goals/new/page.tsx +0 -81
- package/src/app/goals/page.tsx +0 -10
- package/src/app/layout.tsx +0 -53
- package/src/app/manifest.ts +0 -15
- package/src/app/not-found.tsx +0 -8
- package/src/app/page.tsx +0 -33
- package/src/app/recipes/CreateAgentModal.tsx +0 -156
- package/src/app/recipes/CreateCustomTeamModal.tsx +0 -375
- package/src/app/recipes/CreateModalShell.tsx +0 -55
- package/src/app/recipes/CreateTeamModal.tsx +0 -91
- package/src/app/recipes/[id]/RecipeEditor/RecipeEditorCreateModal.tsx +0 -72
- package/src/app/recipes/[id]/RecipeEditor/RecipeEditorPanel.tsx +0 -216
- package/src/app/recipes/[id]/RecipeEditor/index.tsx +0 -271
- package/src/app/recipes/[id]/RecipeEditor/recipe-editor-utils.ts +0 -46
- package/src/app/recipes/[id]/RecipeEditor/types.ts +0 -52
- package/src/app/recipes/[id]/page.tsx +0 -37
- package/src/app/recipes/page.tsx +0 -101
- package/src/app/recipes/recipes-client.tsx +0 -620
- package/src/app/settings/page.tsx +0 -26
- package/src/app/settings/settings-client.tsx +0 -91
- package/src/app/teams/[teamId]/CloneTeamModal.tsx +0 -116
- package/src/app/teams/[teamId]/OrchestratorPanel.tsx +0 -255
- package/src/app/teams/[teamId]/OrchestratorSetupModal.tsx +0 -184
- package/src/app/teams/[teamId]/PublishChangesModal.tsx +0 -43
- package/src/app/teams/[teamId]/page.tsx +0 -49
- package/src/app/teams/[teamId]/team-editor/TeamAgentsTab.tsx +0 -145
- package/src/app/teams/[teamId]/team-editor/TeamCronTab.tsx +0 -72
- package/src/app/teams/[teamId]/team-editor/TeamFilesTab.tsx +0 -74
- package/src/app/teams/[teamId]/team-editor/TeamMemoryTab.tsx +0 -349
- package/src/app/teams/[teamId]/team-editor/TeamRecipeTab.tsx +0 -151
- package/src/app/teams/[teamId]/team-editor/TeamSkillsTab.tsx +0 -68
- package/src/app/teams/[teamId]/team-editor/index.tsx +0 -558
- package/src/app/teams/[teamId]/team-editor/team-editor-data.ts +0 -255
- package/src/app/teams/[teamId]/team-editor/team-editor-utils.ts +0 -78
- package/src/app/teams/[teamId]/team-editor/types.ts +0 -34
- package/src/app/teams/[teamId]/tickets/[ticket]/page.tsx +0 -35
- package/src/app/teams/[teamId]/tickets/page.tsx +0 -15
- package/src/app/teams/[teamId]/workflows/[workflowId]/WorkflowCanvas.tsx +0 -111
- package/src/app/teams/[teamId]/workflows/[workflowId]/page.tsx +0 -27
- package/src/app/teams/[teamId]/workflows/[workflowId]/workflows-editor-client.tsx +0 -1608
- package/src/app/teams/[teamId]/workflows/page.tsx +0 -40
- package/src/app/teams/[teamId]/workflows/workflows-client.tsx +0 -494
- package/src/app/tickets/TicketDetailClient.tsx +0 -147
- package/src/app/tickets/TicketsBoardClient.tsx +0 -200
- package/src/app/tickets/[ticket]/TicketAssignControl.tsx +0 -112
- package/src/app/tickets/[ticket]/page.tsx +0 -36
- package/src/app/tickets/page.tsx +0 -10
- package/src/components/AppShell.tsx +0 -286
- package/src/components/ConfirmationModal.tsx +0 -81
- package/src/components/DeleteEntityModal.tsx +0 -41
- package/src/components/ErrorBoundary.tsx +0 -70
- package/src/components/FileListWithOptionalToggle.tsx +0 -86
- package/src/components/GoalFormFields.tsx +0 -163
- package/src/components/ScaffoldOverlay.tsx +0 -78
- package/src/components/ThemeToggle.tsx +0 -53
- package/src/components/ToastProvider.tsx +0 -163
- package/src/components/__tests__/ConfirmationModal.test.tsx +0 -109
- package/src/components/__tests__/ErrorBoundary.test.tsx +0 -39
- package/src/components/__tests__/FileListWithOptionalToggle.test.tsx +0 -109
- package/src/components/__tests__/GoalFormFields.test.tsx +0 -117
- package/src/components/delete-modals.tsx +0 -59
- package/src/components/icons.tsx +0 -48
- package/src/lib/__tests__/agent-workspace.test.ts +0 -44
- package/src/lib/__tests__/agents.test.ts +0 -36
- package/src/lib/__tests__/api-route-helpers.test.ts +0 -188
- package/src/lib/__tests__/cron.test.ts +0 -45
- package/src/lib/__tests__/editor-utils.test.ts +0 -38
- package/src/lib/__tests__/errors.test.ts +0 -15
- package/src/lib/__tests__/exec.test.ts +0 -13
- package/src/lib/__tests__/fetch-json.test.ts +0 -118
- package/src/lib/__tests__/gateway.test.ts +0 -234
- package/src/lib/__tests__/goal-promote.test.ts +0 -39
- package/src/lib/__tests__/goals-client.test.ts +0 -26
- package/src/lib/__tests__/goals.test.ts +0 -275
- package/src/lib/__tests__/json.test.ts +0 -15
- package/src/lib/__tests__/kitchen-api.test.ts +0 -32
- package/src/lib/__tests__/marketplace.test.ts +0 -116
- package/src/lib/__tests__/openclaw.test.ts +0 -129
- package/src/lib/__tests__/paths.test.ts +0 -136
- package/src/lib/__tests__/poll.test.ts +0 -26
- package/src/lib/__tests__/recipe-clone.test.ts +0 -85
- package/src/lib/__tests__/recipe-team-agents.test.ts +0 -70
- package/src/lib/__tests__/recipes.test.ts +0 -199
- package/src/lib/__tests__/scaffold-client.test.ts +0 -106
- package/src/lib/__tests__/scaffold.test.ts +0 -64
- package/src/lib/__tests__/slugify.test.ts +0 -23
- package/src/lib/__tests__/tickets.test.ts +0 -158
- package/src/lib/__tests__/type-guards.test.ts +0 -18
- package/src/lib/__tests__/use-slugified-id.test.tsx +0 -120
- package/src/lib/agent-workspace.ts +0 -14
- package/src/lib/agents.ts +0 -17
- package/src/lib/api-route-helpers.ts +0 -157
- package/src/lib/cron.ts +0 -40
- package/src/lib/editor-utils.ts +0 -18
- package/src/lib/errors.ts +0 -7
- package/src/lib/exec.ts +0 -4
- package/src/lib/fetch-json.ts +0 -29
- package/src/lib/gateway.ts +0 -100
- package/src/lib/goal-promote.ts +0 -27
- package/src/lib/goals-client.ts +0 -69
- package/src/lib/goals.ts +0 -171
- package/src/lib/json.ts +0 -10
- package/src/lib/kitchen-api.ts +0 -19
- package/src/lib/marketplace.ts +0 -46
- package/src/lib/openclaw.ts +0 -59
- package/src/lib/paths.ts +0 -69
- package/src/lib/poll.ts +0 -18
- package/src/lib/recipe-clone.ts +0 -42
- package/src/lib/recipe-team-agents.ts +0 -30
- package/src/lib/recipes.ts +0 -95
- package/src/lib/scaffold-client.ts +0 -31
- package/src/lib/scaffold.ts +0 -37
- package/src/lib/slugify.ts +0 -25
- package/src/lib/swarms.ts +0 -25
- package/src/lib/tickets.ts +0 -192
- package/src/lib/type-guards.ts +0 -3
- package/src/lib/use-slugified-id.ts +0 -35
- package/src/lib/workflows/README.md +0 -11
- package/src/lib/workflows/__tests__/storage.test.ts +0 -129
- package/src/lib/workflows/__tests__/validate.test.ts +0 -92
- package/src/lib/workflows/api-handlers.ts +0 -35
- package/src/lib/workflows/readdir.ts +0 -23
- package/src/lib/workflows/runs-storage.ts +0 -59
- package/src/lib/workflows/runs-types.ts +0 -42
- package/src/lib/workflows/storage.ts +0 -70
- package/src/lib/workflows/templates/index.ts +0 -1
- package/src/lib/workflows/templates/marketing-cadence-v1.ts +0 -142
- package/src/lib/workflows/types.ts +0 -48
- package/src/lib/workflows/validate.ts +0 -92
- package/src/proxy.ts +0 -28
- /package/.next/static/{z86RoqzzXXrWnpi229zP6 → Jrrrm9HH5bKkSrQhe1j93}/_buildManifest.js +0 -0
- /package/.next/static/{z86RoqzzXXrWnpi229zP6 → Jrrrm9HH5bKkSrQhe1j93}/_clientMiddlewareManifest.json +0 -0
- /package/.next/static/{z86RoqzzXXrWnpi229zP6 → Jrrrm9HH5bKkSrQhe1j93}/_ssgManifest.js +0 -0
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi, beforeEach } from "vitest";
|
|
2
|
-
import { GET, POST, DELETE } from "../teams/workflows/route";
|
|
3
|
-
|
|
4
|
-
vi.mock("@/lib/workflows/storage", () => ({
|
|
5
|
-
listWorkflows: vi.fn(),
|
|
6
|
-
readWorkflow: vi.fn(),
|
|
7
|
-
writeWorkflow: vi.fn(),
|
|
8
|
-
deleteWorkflow: vi.fn(),
|
|
9
|
-
}));
|
|
10
|
-
|
|
11
|
-
import { listWorkflows, readWorkflow, writeWorkflow, deleteWorkflow } from "@/lib/workflows/storage";
|
|
12
|
-
|
|
13
|
-
describe("api teams workflows route", () => {
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
vi.mocked(listWorkflows).mockReset();
|
|
16
|
-
vi.mocked(readWorkflow).mockReset();
|
|
17
|
-
vi.mocked(writeWorkflow).mockReset();
|
|
18
|
-
vi.mocked(deleteWorkflow).mockReset();
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it("GET returns 400 when teamId missing", async () => {
|
|
22
|
-
const res = await GET(new Request("https://test"));
|
|
23
|
-
expect(res.status).toBe(400);
|
|
24
|
-
const json = await res.json();
|
|
25
|
-
expect(json.error).toBe("teamId is required");
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it("GET returns 200 with list when no id", async () => {
|
|
29
|
-
vi.mocked(listWorkflows).mockResolvedValue({ ok: true, dir: "/tmp", files: ["a.workflow.json"] });
|
|
30
|
-
const res = await GET(new Request("https://test?teamId=team1"));
|
|
31
|
-
expect(res.status).toBe(200);
|
|
32
|
-
const json = await res.json();
|
|
33
|
-
expect(json.ok).toBe(true);
|
|
34
|
-
expect(json.files).toEqual(["a.workflow.json"]);
|
|
35
|
-
expect(listWorkflows).toHaveBeenCalledWith("team1");
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it("GET returns 200 with workflow when id provided", async () => {
|
|
39
|
-
const wf = { id: "wf1", name: "Test", nodes: [], edges: [] };
|
|
40
|
-
vi.mocked(readWorkflow).mockResolvedValue({ ok: true, path: "/home/test/wf1.workflow.json", workflow: wf });
|
|
41
|
-
const res = await GET(new Request("https://test?teamId=team1&id=wf1"));
|
|
42
|
-
expect(res.status).toBe(200);
|
|
43
|
-
const json = await res.json();
|
|
44
|
-
expect(json.ok).toBe(true);
|
|
45
|
-
expect(json.workflow).toEqual(wf);
|
|
46
|
-
expect(readWorkflow).toHaveBeenCalledWith("team1", "wf1");
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it("POST returns 400 when teamId missing", async () => {
|
|
50
|
-
const res = await POST(
|
|
51
|
-
new Request("https://test", {
|
|
52
|
-
method: "POST",
|
|
53
|
-
body: JSON.stringify({ workflow: { id: "wf1", name: "Test", nodes: [], edges: [] } }),
|
|
54
|
-
})
|
|
55
|
-
);
|
|
56
|
-
expect(res.status).toBe(400);
|
|
57
|
-
const json = await res.json();
|
|
58
|
-
expect(json.error).toBe("teamId is required");
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it("POST returns 400 when workflow invalid", async () => {
|
|
62
|
-
const res = await POST(
|
|
63
|
-
new Request("https://test", {
|
|
64
|
-
method: "POST",
|
|
65
|
-
body: JSON.stringify({ teamId: "team1", workflow: {} }),
|
|
66
|
-
})
|
|
67
|
-
);
|
|
68
|
-
expect(res.status).toBe(400);
|
|
69
|
-
const json = await res.json();
|
|
70
|
-
expect(json.error).toMatch(/workflow.*required/i);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it("POST returns 200 when workflow valid", async () => {
|
|
74
|
-
const wf = { id: "wf1", name: "Test", nodes: [], edges: [] };
|
|
75
|
-
vi.mocked(writeWorkflow).mockResolvedValue({ ok: true, path: "/home/test/wf1.workflow.json" });
|
|
76
|
-
const res = await POST(
|
|
77
|
-
new Request("https://test", {
|
|
78
|
-
method: "POST",
|
|
79
|
-
body: JSON.stringify({ teamId: "team1", workflow: wf }),
|
|
80
|
-
})
|
|
81
|
-
);
|
|
82
|
-
expect(res.status).toBe(200);
|
|
83
|
-
const json = await res.json();
|
|
84
|
-
expect(json.ok).toBe(true);
|
|
85
|
-
expect(writeWorkflow).toHaveBeenCalledWith("team1", expect.objectContaining({ id: "wf1", name: "Test" }));
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it("DELETE returns 400 when teamId missing", async () => {
|
|
89
|
-
const res = await DELETE(new Request("https://test"));
|
|
90
|
-
expect(res.status).toBe(400);
|
|
91
|
-
const json = await res.json();
|
|
92
|
-
expect(json.error).toBe("teamId is required");
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it("DELETE returns 400 when id missing", async () => {
|
|
96
|
-
const res = await DELETE(new Request("https://test?teamId=team1"));
|
|
97
|
-
expect(res.status).toBe(400);
|
|
98
|
-
const json = await res.json();
|
|
99
|
-
expect(json.error).toBe("id is required");
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it("DELETE returns 200 when valid", async () => {
|
|
103
|
-
vi.mocked(deleteWorkflow).mockResolvedValue({ ok: true, path: "/home/test/wf1.workflow.json", existed: true });
|
|
104
|
-
const res = await DELETE(new Request("https://test?teamId=team1&id=wf1"));
|
|
105
|
-
expect(res.status).toBe(200);
|
|
106
|
-
const json = await res.json();
|
|
107
|
-
expect(json.ok).toBe(true);
|
|
108
|
-
expect(deleteWorkflow).toHaveBeenCalledWith("team1", "wf1");
|
|
109
|
-
});
|
|
110
|
-
});
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi, beforeEach } from "vitest";
|
|
2
|
-
import { POST } from "../tickets/move/route";
|
|
3
|
-
|
|
4
|
-
vi.mock("@/lib/openclaw", () => ({ runOpenClaw: vi.fn() }));
|
|
5
|
-
|
|
6
|
-
import { runOpenClaw } from "@/lib/openclaw";
|
|
7
|
-
|
|
8
|
-
describe("api tickets move route", () => {
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
vi.mocked(runOpenClaw).mockReset();
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
it("returns 400 when ticket missing", async () => {
|
|
14
|
-
const res = await POST(new Request("https://test", { method: "POST", body: JSON.stringify({}) }));
|
|
15
|
-
expect(res.status).toBe(400);
|
|
16
|
-
const json = await res.json();
|
|
17
|
-
expect(json.error).toBe("Missing ticket");
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it("returns 400 when destination invalid", async () => {
|
|
21
|
-
const res = await POST(
|
|
22
|
-
new Request("https://test", {
|
|
23
|
-
method: "POST",
|
|
24
|
-
body: JSON.stringify({ ticket: "T-1", to: "invalid" }),
|
|
25
|
-
})
|
|
26
|
-
);
|
|
27
|
-
expect(res.status).toBe(400);
|
|
28
|
-
const json = await res.json();
|
|
29
|
-
expect(json.error).toBe("Invalid destination stage");
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it("returns 200 when move succeeds", async () => {
|
|
33
|
-
vi.mocked(runOpenClaw).mockResolvedValue({ ok: true, exitCode: 0, stdout: "", stderr: "" });
|
|
34
|
-
const res = await POST(
|
|
35
|
-
new Request("https://test", {
|
|
36
|
-
method: "POST",
|
|
37
|
-
body: JSON.stringify({ ticket: "T-1", to: "in-progress" }),
|
|
38
|
-
})
|
|
39
|
-
);
|
|
40
|
-
expect(res.status).toBe(200);
|
|
41
|
-
const json = await res.json();
|
|
42
|
-
expect(json.ok).toBe(true);
|
|
43
|
-
expect(runOpenClaw).toHaveBeenCalledWith(
|
|
44
|
-
expect.arrayContaining(["recipes", "move-ticket", "--ticket", "T-1", "--to", "in-progress"])
|
|
45
|
-
);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it("returns 500 when exec fails", async () => {
|
|
49
|
-
vi.mocked(runOpenClaw).mockRejectedValue(new Error("Command failed"));
|
|
50
|
-
const res = await POST(
|
|
51
|
-
new Request("https://test", {
|
|
52
|
-
method: "POST",
|
|
53
|
-
body: JSON.stringify({ ticket: "T-1", to: "done" }),
|
|
54
|
-
})
|
|
55
|
-
);
|
|
56
|
-
expect(res.status).toBe(500);
|
|
57
|
-
const json = await res.json();
|
|
58
|
-
expect(json.error).toBe("Command failed");
|
|
59
|
-
});
|
|
60
|
-
});
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { NextResponse } from "next/server";
|
|
4
|
-
|
|
5
|
-
import { runOpenClaw } from "@/lib/openclaw";
|
|
6
|
-
import { parseTeamRoleWorkspace } from "@/lib/agent-workspace";
|
|
7
|
-
|
|
8
|
-
async function resolveAgentWorkspace(agentId: string): Promise<string | null> {
|
|
9
|
-
try {
|
|
10
|
-
const { stdout } = await runOpenClaw(["agents", "list", "--json"]);
|
|
11
|
-
const list = JSON.parse(stdout) as Array<{ id: string; workspace?: string }>;
|
|
12
|
-
const agent = list.find((a) => a.id === agentId);
|
|
13
|
-
return agent?.workspace ? String(agent.workspace) : null;
|
|
14
|
-
} catch {
|
|
15
|
-
return null;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
async function moveTeamRoleToTrashOrRemove(info: {
|
|
20
|
-
teamDir: string;
|
|
21
|
-
role: string;
|
|
22
|
-
roleDir: string;
|
|
23
|
-
}): Promise<void> {
|
|
24
|
-
const trashDir = path.join(info.teamDir, ".trash", "roles");
|
|
25
|
-
const ts = new Date().toISOString().replace(/[:.]/g, "-");
|
|
26
|
-
const dst = path.join(trashDir, `${info.role}-${ts}`);
|
|
27
|
-
try {
|
|
28
|
-
await fs.mkdir(trashDir, { recursive: true });
|
|
29
|
-
await fs.rename(info.roleDir, dst);
|
|
30
|
-
} catch {
|
|
31
|
-
try {
|
|
32
|
-
await fs.rm(info.roleDir, { recursive: true, force: true });
|
|
33
|
-
} catch {
|
|
34
|
-
// ignore
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export async function DELETE(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
40
|
-
try {
|
|
41
|
-
const { id } = await params;
|
|
42
|
-
const agentId = String(id ?? "").trim();
|
|
43
|
-
if (!agentId) return NextResponse.json({ ok: false, error: "agent id is required" }, { status: 400 });
|
|
44
|
-
|
|
45
|
-
const workspace = await resolveAgentWorkspace(agentId);
|
|
46
|
-
|
|
47
|
-
const result = await runOpenClaw(["agents", "delete", agentId, "--force", "--json"]);
|
|
48
|
-
if (!result.ok) {
|
|
49
|
-
return NextResponse.json(
|
|
50
|
-
{
|
|
51
|
-
ok: false,
|
|
52
|
-
error: `Failed to delete agent: ${agentId}`,
|
|
53
|
-
stderr: result.stderr || undefined,
|
|
54
|
-
stdout: result.stdout || undefined,
|
|
55
|
-
},
|
|
56
|
-
{ status: 500 },
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
let parsed: unknown = null;
|
|
61
|
-
try {
|
|
62
|
-
parsed = JSON.parse(result.stdout);
|
|
63
|
-
} catch {
|
|
64
|
-
parsed = null;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (workspace) {
|
|
68
|
-
const info = parseTeamRoleWorkspace(workspace);
|
|
69
|
-
if (info.kind === "teamRole") await moveTeamRoleToTrashOrRemove(info);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return NextResponse.json({ ok: true, result: parsed ?? result.stdout });
|
|
73
|
-
} catch (err: unknown) {
|
|
74
|
-
return NextResponse.json(
|
|
75
|
-
{
|
|
76
|
-
ok: false,
|
|
77
|
-
error: "Failed to delete agent",
|
|
78
|
-
message: err instanceof Error ? err.message : String(err),
|
|
79
|
-
},
|
|
80
|
-
{ status: 500 },
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import os from "node:os";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
|
|
5
|
-
import { NextResponse } from "next/server";
|
|
6
|
-
|
|
7
|
-
import { getKitchenApi } from "@/lib/kitchen-api";
|
|
8
|
-
import { teamDirFromBaseWorkspace } from "@/lib/paths";
|
|
9
|
-
|
|
10
|
-
function normalizeAgentId(id: string) {
|
|
11
|
-
const s = id.trim();
|
|
12
|
-
if (!s) throw new Error("agent id is required");
|
|
13
|
-
if (!/^[a-z0-9][a-z0-9-]{0,62}$/i.test(s)) {
|
|
14
|
-
throw new Error("agent id must match /^[a-z0-9][a-z0-9-]{0,62}$/i");
|
|
15
|
-
}
|
|
16
|
-
return s;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function buildAgentEntry(
|
|
20
|
-
body: { newAgentId?: string; agentId?: string; name?: string; emoji?: string; theme?: string; avatar?: string; model?: string },
|
|
21
|
-
newAgentId: string,
|
|
22
|
-
newWorkspace: string
|
|
23
|
-
): Record<string, unknown> {
|
|
24
|
-
const identity: Record<string, unknown> = {};
|
|
25
|
-
if (typeof body.name === "string" && body.name.trim()) identity.name = body.name.trim();
|
|
26
|
-
if (typeof body.theme === "string" && body.theme.trim()) identity.theme = body.theme.trim();
|
|
27
|
-
if (typeof body.emoji === "string" && body.emoji.trim()) identity.emoji = body.emoji.trim();
|
|
28
|
-
if (typeof body.avatar === "string" && body.avatar.trim()) identity.avatar = body.avatar.trim();
|
|
29
|
-
|
|
30
|
-
return {
|
|
31
|
-
id: newAgentId,
|
|
32
|
-
workspace: newWorkspace,
|
|
33
|
-
...(body.model ? { model: body.model } : {}),
|
|
34
|
-
identity,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export async function POST(req: Request) {
|
|
39
|
-
try {
|
|
40
|
-
const body = (await req.json()) as {
|
|
41
|
-
newAgentId?: string;
|
|
42
|
-
agentId?: string;
|
|
43
|
-
name?: string;
|
|
44
|
-
emoji?: string;
|
|
45
|
-
theme?: string;
|
|
46
|
-
avatar?: string;
|
|
47
|
-
model?: string;
|
|
48
|
-
overwrite?: boolean;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const newAgentId = normalizeAgentId(String(body.newAgentId ?? body.agentId ?? ""));
|
|
52
|
-
const overwrite = Boolean(body.overwrite);
|
|
53
|
-
|
|
54
|
-
const homeDir = os.homedir();
|
|
55
|
-
if (!homeDir) {
|
|
56
|
-
return NextResponse.json({ ok: false, error: "HOME is not set" }, { status: 500 });
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const configPath = path.join(homeDir, ".openclaw", "openclaw.json");
|
|
60
|
-
const raw = await fs.readFile(configPath, "utf8");
|
|
61
|
-
const cfg = JSON.parse(raw) as {
|
|
62
|
-
agents?: { defaults?: { workspace?: string }; list?: Array<Record<string, unknown>> };
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const baseWorkspace = String(cfg?.agents?.defaults?.workspace ?? "").trim();
|
|
66
|
-
if (!baseWorkspace) {
|
|
67
|
-
return NextResponse.json({ ok: false, error: "agents.defaults.workspace not set" }, { status: 500 });
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const newWorkspace = teamDirFromBaseWorkspace(baseWorkspace, newAgentId);
|
|
71
|
-
const agentsList: Array<Record<string, unknown>> = Array.isArray(cfg?.agents?.list) ? cfg.agents.list : [];
|
|
72
|
-
const exists = agentsList.some((a) => String(a?.id ?? "").toLowerCase() === newAgentId.toLowerCase());
|
|
73
|
-
if (exists && !overwrite) {
|
|
74
|
-
return NextResponse.json({ ok: false, error: `Agent already exists: ${newAgentId}` }, { status: 409 });
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const nextEntry = buildAgentEntry(body, newAgentId, newWorkspace);
|
|
78
|
-
const nextList = exists
|
|
79
|
-
? agentsList.map((a) => (String(a?.id ?? "").toLowerCase() === newAgentId.toLowerCase() ? nextEntry : a))
|
|
80
|
-
: [...agentsList, nextEntry];
|
|
81
|
-
|
|
82
|
-
// Ensure workspace directory exists and seed IDENTITY.md for clarity.
|
|
83
|
-
await fs.mkdir(newWorkspace, { recursive: true });
|
|
84
|
-
const identityMd = `# IDENTITY.md\n\n- **Name:** ${String(body.name ?? "").trim() || newAgentId}\n- **Creature:**\n- **Vibe:**\n- **Emoji:** ${String(body.emoji ?? "").trim()}\n- **Avatar:** ${String(body.avatar ?? "").trim()}\n`;
|
|
85
|
-
await fs.writeFile(path.join(newWorkspace, "IDENTITY.md"), identityMd, "utf8");
|
|
86
|
-
|
|
87
|
-
// Persist to ~/.openclaw/openclaw.json
|
|
88
|
-
const nextCfg = {
|
|
89
|
-
...cfg,
|
|
90
|
-
agents: {
|
|
91
|
-
...(cfg.agents ?? {}),
|
|
92
|
-
list: nextList,
|
|
93
|
-
},
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
// Write atomically.
|
|
97
|
-
const tmpPath = `${configPath}.tmp`;
|
|
98
|
-
const bakPath = `${configPath}.bak.${new Date().toISOString().replace(/[:.]/g, "-")}`;
|
|
99
|
-
await fs.writeFile(tmpPath, JSON.stringify(nextCfg, null, 2) + "\n", "utf8");
|
|
100
|
-
await fs.copyFile(configPath, bakPath).catch(() => {});
|
|
101
|
-
await fs.rename(tmpPath, configPath);
|
|
102
|
-
|
|
103
|
-
// Restart gateway so the new agent is live.
|
|
104
|
-
const api = getKitchenApi();
|
|
105
|
-
await api.runtime.system.runCommandWithTimeout(["openclaw", "gateway", "restart"], { timeoutMs: 120000 });
|
|
106
|
-
|
|
107
|
-
return NextResponse.json({ ok: true, agentId: newAgentId, workspace: newWorkspace, restarted: true });
|
|
108
|
-
} catch (err) {
|
|
109
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
110
|
-
// Prefer 400 for validation/input errors; otherwise 500.
|
|
111
|
-
const status = /required|match \//i.test(msg) ? 400 : 500;
|
|
112
|
-
return NextResponse.json({ ok: false, error: msg }, { status });
|
|
113
|
-
}
|
|
114
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { NextResponse } from "next/server";
|
|
4
|
-
import { errorMessage } from "@/lib/errors";
|
|
5
|
-
import { assertSafeRelativeFileName } from "@/lib/paths";
|
|
6
|
-
import { getAgentContextFromBody, getAgentContextFromQuery } from "@/lib/api-route-helpers";
|
|
7
|
-
|
|
8
|
-
export async function GET(req: Request) {
|
|
9
|
-
const ctx = await getAgentContextFromQuery(req);
|
|
10
|
-
if (ctx instanceof NextResponse) return ctx;
|
|
11
|
-
const { agentId, ws } = ctx;
|
|
12
|
-
|
|
13
|
-
const { searchParams } = new URL(req.url);
|
|
14
|
-
const name = String(searchParams.get("name") ?? "").trim();
|
|
15
|
-
if (!name) return NextResponse.json({ ok: false, error: "name is required" }, { status: 400 });
|
|
16
|
-
|
|
17
|
-
const safe = assertSafeRelativeFileName(name);
|
|
18
|
-
const filePath = path.join(ws, safe);
|
|
19
|
-
|
|
20
|
-
try {
|
|
21
|
-
const content = await fs.readFile(filePath, "utf8");
|
|
22
|
-
return NextResponse.json({ ok: true, agentId, workspace: ws, name: safe, filePath, content });
|
|
23
|
-
} catch (e: unknown) {
|
|
24
|
-
return NextResponse.json({ ok: false, error: errorMessage(e) }, { status: 404 });
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export async function PUT(req: Request) {
|
|
29
|
-
const body = (await req.json()) as { agentId?: string; name?: string; content?: string };
|
|
30
|
-
const name = String(body.name ?? "").trim();
|
|
31
|
-
const content = typeof body.content === "string" ? body.content : null;
|
|
32
|
-
if (!name) return NextResponse.json({ ok: false, error: "name is required" }, { status: 400 });
|
|
33
|
-
if (content === null) return NextResponse.json({ ok: false, error: "content is required" }, { status: 400 });
|
|
34
|
-
|
|
35
|
-
const ctx = await getAgentContextFromBody(body);
|
|
36
|
-
if (ctx instanceof NextResponse) return ctx;
|
|
37
|
-
const { agentId, ws } = ctx;
|
|
38
|
-
|
|
39
|
-
const safe = assertSafeRelativeFileName(name);
|
|
40
|
-
const filePath = path.join(ws, safe);
|
|
41
|
-
|
|
42
|
-
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
43
|
-
await fs.writeFile(filePath, content, "utf8");
|
|
44
|
-
return NextResponse.json({ ok: true, agentId, workspace: ws, name: safe, filePath });
|
|
45
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
import { getAgentContextFromQuery, listWorkspaceFiles } from "@/lib/api-route-helpers";
|
|
3
|
-
|
|
4
|
-
export async function GET(req: Request) {
|
|
5
|
-
const ctx = await getAgentContextFromQuery(req);
|
|
6
|
-
if (ctx instanceof NextResponse) return ctx;
|
|
7
|
-
const { agentId, ws } = ctx;
|
|
8
|
-
|
|
9
|
-
const candidates = [
|
|
10
|
-
{ name: "SOUL.md", required: true, rationale: "Agent persona/instructions" },
|
|
11
|
-
{ name: "AGENTS.md", required: true, rationale: "Agent operating rules" },
|
|
12
|
-
{ name: "TOOLS.md", required: true, rationale: "Agent local notes" },
|
|
13
|
-
{ name: "STATUS.md", required: false, rationale: "Optional current status snapshot" },
|
|
14
|
-
{ name: "NOTES.md", required: false, rationale: "Optional scratchpad" },
|
|
15
|
-
{ name: "IDENTITY.md", required: false, rationale: "Optional identity (name/emoji/avatar)" },
|
|
16
|
-
{ name: "USER.md", required: false, rationale: "Optional user profile" },
|
|
17
|
-
{ name: "HEARTBEAT.md", required: false, rationale: "Optional periodic checklist" },
|
|
18
|
-
{ name: "MEMORY.md", required: false, rationale: "Optional curated memory" },
|
|
19
|
-
];
|
|
20
|
-
|
|
21
|
-
const files = await listWorkspaceFiles(ws, candidates);
|
|
22
|
-
return NextResponse.json({ ok: true, agentId, workspace: ws, files });
|
|
23
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
|
|
3
|
-
import { runOpenClaw } from "@/lib/openclaw";
|
|
4
|
-
|
|
5
|
-
type Body = {
|
|
6
|
-
agentId: string;
|
|
7
|
-
name?: string;
|
|
8
|
-
emoji?: string;
|
|
9
|
-
theme?: string;
|
|
10
|
-
avatar?: string;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export async function POST(req: Request) {
|
|
14
|
-
try {
|
|
15
|
-
const body = (await req.json()) as Body;
|
|
16
|
-
const agentId = body.agentId?.trim();
|
|
17
|
-
|
|
18
|
-
if (!agentId) {
|
|
19
|
-
return NextResponse.json({ error: "agentId is required" }, { status: 400 });
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const args = ["agents", "set-identity", agentId];
|
|
23
|
-
|
|
24
|
-
if (body.name?.trim()) args.push("--name", body.name.trim());
|
|
25
|
-
if (body.emoji?.trim()) args.push("--emoji", body.emoji.trim());
|
|
26
|
-
if (body.theme?.trim()) args.push("--theme", body.theme.trim());
|
|
27
|
-
if (body.avatar?.trim()) args.push("--avatar", body.avatar.trim());
|
|
28
|
-
|
|
29
|
-
const { stdout, stderr } = await runOpenClaw(args);
|
|
30
|
-
|
|
31
|
-
return NextResponse.json({ ok: true, stdout, stderr });
|
|
32
|
-
} catch (err) {
|
|
33
|
-
return NextResponse.json(
|
|
34
|
-
{
|
|
35
|
-
error: "Failed to set agent identity",
|
|
36
|
-
message: err instanceof Error ? err.message : String(err),
|
|
37
|
-
},
|
|
38
|
-
{ status: 500 },
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
import { type AgentListItem } from "@/lib/agents";
|
|
3
|
-
import { errorMessage } from "@/lib/errors";
|
|
4
|
-
import { runOpenClaw } from "@/lib/openclaw";
|
|
5
|
-
|
|
6
|
-
export async function GET() {
|
|
7
|
-
try {
|
|
8
|
-
const { stdout, stderr } = await runOpenClaw(["agents", "list", "--json"]);
|
|
9
|
-
|
|
10
|
-
const agents = JSON.parse(stdout) as AgentListItem[];
|
|
11
|
-
|
|
12
|
-
return NextResponse.json({ agents, stderr: stderr || undefined });
|
|
13
|
-
} catch (err) {
|
|
14
|
-
return NextResponse.json(
|
|
15
|
-
{
|
|
16
|
-
error: "Failed to list agents",
|
|
17
|
-
message: errorMessage(err),
|
|
18
|
-
},
|
|
19
|
-
{ status: 500 },
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
import { runOpenClaw } from "@/lib/openclaw";
|
|
3
|
-
import { parseTeamRoleWorkspace } from "@/lib/agent-workspace";
|
|
4
|
-
import { installSkillErrorResponse } from "@/lib/api-route-helpers";
|
|
5
|
-
|
|
6
|
-
export async function POST(req: Request) {
|
|
7
|
-
const body = (await req.json()) as { agentId?: string; skill?: string };
|
|
8
|
-
const agentId = String(body.agentId ?? "").trim();
|
|
9
|
-
const skill = String(body.skill ?? "").trim();
|
|
10
|
-
|
|
11
|
-
if (!agentId) return NextResponse.json({ ok: false, error: "agentId is required" }, { status: 400 });
|
|
12
|
-
if (!skill) return NextResponse.json({ ok: false, error: "skill is required" }, { status: 400 });
|
|
13
|
-
|
|
14
|
-
// For role-based team agents, install at team scope to avoid creating a separate
|
|
15
|
-
// workspace-<agentId> directory that diverges from roles/<role>.
|
|
16
|
-
let args = ["recipes", "install-skill", skill, "--agent-id", agentId, "--yes"];
|
|
17
|
-
try {
|
|
18
|
-
const { stdout } = await runOpenClaw(["agents", "list", "--json"]);
|
|
19
|
-
const list = JSON.parse(stdout) as Array<{ id: string; workspace?: string }>;
|
|
20
|
-
const agent = list.find((a) => a.id === agentId);
|
|
21
|
-
const ws = agent?.workspace ? String(agent.workspace) : "";
|
|
22
|
-
const info = parseTeamRoleWorkspace(ws);
|
|
23
|
-
if (info.kind === "teamRole") {
|
|
24
|
-
args = ["recipes", "install-skill", skill, "--team-id", info.teamId, "--yes"];
|
|
25
|
-
}
|
|
26
|
-
} catch {
|
|
27
|
-
// If anything goes wrong, fall back to agent scope.
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const res = await runOpenClaw(args);
|
|
31
|
-
if (!res.ok) return installSkillErrorResponse(args, res, { scopeArgs: args });
|
|
32
|
-
|
|
33
|
-
return NextResponse.json({ ok: true, agentId, skill, scopeArgs: args, stdout: res.stdout, stderr: res.stderr });
|
|
34
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { NextResponse } from "next/server";
|
|
4
|
-
import { parseTeamRoleWorkspace } from "@/lib/agent-workspace";
|
|
5
|
-
import { getAgentContextFromQuery } from "@/lib/api-route-helpers";
|
|
6
|
-
import { errorMessage } from "@/lib/errors";
|
|
7
|
-
|
|
8
|
-
export async function GET(req: Request) {
|
|
9
|
-
const ctx = await getAgentContextFromQuery(req);
|
|
10
|
-
if (ctx instanceof NextResponse) return ctx;
|
|
11
|
-
const { agentId, ws } = ctx;
|
|
12
|
-
|
|
13
|
-
const info = parseTeamRoleWorkspace(ws);
|
|
14
|
-
const dirs: string[] = [path.join(ws, "skills")];
|
|
15
|
-
if (info.kind === "teamRole") {
|
|
16
|
-
dirs.push(path.join(info.teamDir, "skills"));
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const skills = new Set<string>();
|
|
20
|
-
const notes: string[] = [];
|
|
21
|
-
|
|
22
|
-
for (const skillsDir of dirs) {
|
|
23
|
-
try {
|
|
24
|
-
const entries = await fs.readdir(skillsDir, { withFileTypes: true });
|
|
25
|
-
for (const e of entries) if (e.isDirectory()) skills.add(e.name);
|
|
26
|
-
} catch (e: unknown) {
|
|
27
|
-
notes.push(`${skillsDir}: ${errorMessage(e)}`);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return NextResponse.json({
|
|
32
|
-
ok: true,
|
|
33
|
-
agentId,
|
|
34
|
-
workspace: ws,
|
|
35
|
-
skillsDirs: dirs,
|
|
36
|
-
skills: Array.from(skills).sort((a, b) => a.localeCompare(b)),
|
|
37
|
-
note: notes.length ? notes.join("; ") : undefined,
|
|
38
|
-
});
|
|
39
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
import { gatewayConfigGet, gatewayConfigPatch } from "@/lib/gateway";
|
|
3
|
-
|
|
4
|
-
function normalizeAgentId(id: string) {
|
|
5
|
-
const s = id.trim();
|
|
6
|
-
if (!s) throw new Error("agentId is required");
|
|
7
|
-
return s;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export async function POST(req: Request) {
|
|
11
|
-
const body = (await req.json()) as {
|
|
12
|
-
agentId?: string;
|
|
13
|
-
patch?: {
|
|
14
|
-
workspace?: string;
|
|
15
|
-
model?: string;
|
|
16
|
-
identity?: { name?: string; theme?: string; emoji?: string; avatar?: string };
|
|
17
|
-
};
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const agentId = normalizeAgentId(String(body.agentId ?? ""));
|
|
21
|
-
const patch = body.patch ?? {};
|
|
22
|
-
|
|
23
|
-
const { raw } = await gatewayConfigGet();
|
|
24
|
-
const cfg = JSON.parse(raw) as { agents?: { list?: Array<Record<string, unknown>> } };
|
|
25
|
-
|
|
26
|
-
const list = Array.isArray(cfg.agents?.list) ? (cfg.agents?.list as Array<Record<string, unknown>>) : [];
|
|
27
|
-
const idx = list.findIndex((a) => String(a.id ?? "").toLowerCase() === agentId.toLowerCase());
|
|
28
|
-
if (idx === -1) return NextResponse.json({ ok: false, error: `Agent not found in config: ${agentId}` }, { status: 404 });
|
|
29
|
-
|
|
30
|
-
const current = list[idx] ?? {};
|
|
31
|
-
const currentIdentity = (current.identity ?? {}) as Record<string, unknown>;
|
|
32
|
-
|
|
33
|
-
const next: Record<string, unknown> = {
|
|
34
|
-
...current,
|
|
35
|
-
...(typeof patch.workspace === "string" && patch.workspace.trim() ? { workspace: patch.workspace.trim() } : {}),
|
|
36
|
-
...(typeof patch.model === "string" && patch.model.trim() ? { model: patch.model.trim() } : {}),
|
|
37
|
-
identity: {
|
|
38
|
-
...currentIdentity,
|
|
39
|
-
...(typeof patch.identity?.name === "string" ? { name: patch.identity.name } : {}),
|
|
40
|
-
...(typeof patch.identity?.theme === "string" ? { theme: patch.identity.theme } : {}),
|
|
41
|
-
...(typeof patch.identity?.emoji === "string" ? { emoji: patch.identity.emoji } : {}),
|
|
42
|
-
...(typeof patch.identity?.avatar === "string" ? { avatar: patch.identity.avatar } : {}),
|
|
43
|
-
},
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const nextList = list.slice();
|
|
47
|
-
nextList[idx] = next;
|
|
48
|
-
|
|
49
|
-
await gatewayConfigPatch({ agents: { list: nextList } }, `ClawKitchen: update agent ${agentId}`);
|
|
50
|
-
|
|
51
|
-
return NextResponse.json({ ok: true, agentId });
|
|
52
|
-
}
|