@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,63 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
import { errorMessage } from "@/lib/errors";
|
|
3
|
-
import { gatewayConfigGet, gatewayConfigPatch } from "@/lib/gateway";
|
|
4
|
-
import { safeJsonParse } from "@/lib/json";
|
|
5
|
-
import { isRecord } from "@/lib/type-guards";
|
|
6
|
-
|
|
7
|
-
export async function GET() {
|
|
8
|
-
try {
|
|
9
|
-
const { raw, hash } = await gatewayConfigGet();
|
|
10
|
-
const parsed = safeJsonParse(raw);
|
|
11
|
-
const root = isRecord(parsed) ? parsed : {};
|
|
12
|
-
const channels = isRecord(root.channels) ? root.channels : {};
|
|
13
|
-
return NextResponse.json({ ok: true, hash, channels });
|
|
14
|
-
} catch (e: unknown) {
|
|
15
|
-
const msg = errorMessage(e);
|
|
16
|
-
return NextResponse.json({ ok: false, error: msg }, { status: 500 });
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
type UpsertBody = {
|
|
21
|
-
provider: string;
|
|
22
|
-
config: Record<string, unknown>;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export async function PUT(req: Request) {
|
|
26
|
-
try {
|
|
27
|
-
const body = (await req.json()) as UpsertBody;
|
|
28
|
-
const provider = String(body?.provider ?? "").trim();
|
|
29
|
-
if (!provider) return NextResponse.json({ ok: false, error: "provider is required" }, { status: 400 });
|
|
30
|
-
|
|
31
|
-
const cfg = isRecord(body?.config) ? body.config : null;
|
|
32
|
-
if (!cfg) return NextResponse.json({ ok: false, error: "config must be an object" }, { status: 400 });
|
|
33
|
-
|
|
34
|
-
// v1 validation (Telegram as reference)
|
|
35
|
-
if (provider === "telegram") {
|
|
36
|
-
const botToken = String(cfg.botToken ?? "").trim();
|
|
37
|
-
if (!botToken) return NextResponse.json({ ok: false, error: "telegram.botToken is required" }, { status: 400 });
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
await gatewayConfigPatch({ channels: { [provider]: cfg } }, `ClawKitchen Channels upsert: ${provider}`);
|
|
41
|
-
return NextResponse.json({ ok: true });
|
|
42
|
-
} catch (e: unknown) {
|
|
43
|
-
const msg = errorMessage(e);
|
|
44
|
-
return NextResponse.json({ ok: false, error: msg }, { status: 500 });
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
type DeleteBody = { provider: string };
|
|
49
|
-
|
|
50
|
-
export async function DELETE(req: Request) {
|
|
51
|
-
try {
|
|
52
|
-
const body = (await req.json()) as DeleteBody;
|
|
53
|
-
const provider = String(body?.provider ?? "").trim();
|
|
54
|
-
if (!provider) return NextResponse.json({ ok: false, error: "provider is required" }, { status: 400 });
|
|
55
|
-
|
|
56
|
-
// Patch semantics: setting a provider to null removes/clears it in the gateway config patcher.
|
|
57
|
-
await gatewayConfigPatch({ channels: { [provider]: null } }, `ClawKitchen Channels delete: ${provider}`);
|
|
58
|
-
return NextResponse.json({ ok: true });
|
|
59
|
-
} catch (e: unknown) {
|
|
60
|
-
const msg = errorMessage(e);
|
|
61
|
-
return NextResponse.json({ ok: false, error: msg }, { status: 500 });
|
|
62
|
-
}
|
|
63
|
-
}
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi, beforeEach } from "vitest";
|
|
2
|
-
import {
|
|
3
|
-
buildIdToScopeMap,
|
|
4
|
-
getInstalledIdsForTeam,
|
|
5
|
-
enrichJobsWithScope,
|
|
6
|
-
markOrphanedInTeamWorkspaces,
|
|
7
|
-
getBaseWorkspaceFromGateway,
|
|
8
|
-
} from "../helpers";
|
|
9
|
-
|
|
10
|
-
vi.mock("@/lib/openclaw", () => ({
|
|
11
|
-
runOpenClaw: vi.fn(),
|
|
12
|
-
}));
|
|
13
|
-
vi.mock("node:fs/promises", () => ({
|
|
14
|
-
default: {
|
|
15
|
-
readdir: vi.fn(),
|
|
16
|
-
readFile: vi.fn(),
|
|
17
|
-
writeFile: vi.fn(),
|
|
18
|
-
stat: vi.fn(),
|
|
19
|
-
},
|
|
20
|
-
}));
|
|
21
|
-
|
|
22
|
-
import { runOpenClaw } from "@/lib/openclaw";
|
|
23
|
-
import fs from "node:fs/promises";
|
|
24
|
-
|
|
25
|
-
describe("cron helpers", () => {
|
|
26
|
-
beforeEach(() => {
|
|
27
|
-
vi.mocked(runOpenClaw).mockReset();
|
|
28
|
-
vi.mocked(fs.readdir).mockReset();
|
|
29
|
-
vi.mocked(fs.readFile).mockReset();
|
|
30
|
-
vi.mocked(fs.writeFile).mockReset();
|
|
31
|
-
vi.mocked(fs.stat).mockReset();
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
describe("getInstalledIdsForTeam", () => {
|
|
35
|
-
it("returns installed cron ids from provenance file", async () => {
|
|
36
|
-
vi.mocked(fs.readFile).mockResolvedValue(
|
|
37
|
-
JSON.stringify({
|
|
38
|
-
entries: {
|
|
39
|
-
"recipe.lead": { installedCronId: "cron-1", orphaned: false },
|
|
40
|
-
"recipe.qa": { installedCronId: "cron-2", orphaned: false },
|
|
41
|
-
},
|
|
42
|
-
})
|
|
43
|
-
);
|
|
44
|
-
const result = await getInstalledIdsForTeam("/path/to/cron-jobs.json");
|
|
45
|
-
expect(result).toEqual(["cron-1", "cron-2"]);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it("filters out orphaned entries", async () => {
|
|
49
|
-
vi.mocked(fs.readFile).mockResolvedValue(
|
|
50
|
-
JSON.stringify({
|
|
51
|
-
entries: {
|
|
52
|
-
a: { installedCronId: "cron-1", orphaned: false },
|
|
53
|
-
b: { installedCronId: "cron-2", orphaned: true },
|
|
54
|
-
},
|
|
55
|
-
})
|
|
56
|
-
);
|
|
57
|
-
const result = await getInstalledIdsForTeam("/path/to/file");
|
|
58
|
-
expect(result).toEqual(["cron-1"]);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it("returns empty array on read error", async () => {
|
|
62
|
-
vi.mocked(fs.readFile).mockRejectedValue(new Error("not found"));
|
|
63
|
-
const result = await getInstalledIdsForTeam("/path/to/file");
|
|
64
|
-
expect(result).toEqual([]);
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
describe("enrichJobsWithScope", () => {
|
|
69
|
-
it("adds scope to jobs when id matches", () => {
|
|
70
|
-
const idToScope = new Map([
|
|
71
|
-
["job-1", { kind: "team" as const, id: "team1", label: "team1", href: "/teams/team1" }],
|
|
72
|
-
]);
|
|
73
|
-
const jobs = [{ id: "job-1", name: "Job 1" }, { id: "job-2", name: "Job 2" }];
|
|
74
|
-
const result = enrichJobsWithScope(jobs, idToScope);
|
|
75
|
-
expect(result[0]).toHaveProperty("scope");
|
|
76
|
-
expect((result[0] as { scope: { id: string } }).scope.id).toBe("team1");
|
|
77
|
-
expect(result[1]).not.toHaveProperty("scope");
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it("preserves job when no scope", () => {
|
|
81
|
-
const idToScope = new Map();
|
|
82
|
-
const jobs = [{ id: "job-1" }];
|
|
83
|
-
const result = enrichJobsWithScope(jobs, idToScope);
|
|
84
|
-
expect(result[0]).toEqual({ id: "job-1" });
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
describe("buildIdToScopeMap", () => {
|
|
89
|
-
it("collects team and agent scopes", async () => {
|
|
90
|
-
vi.mocked(fs.readdir).mockResolvedValue([
|
|
91
|
-
{ name: "workspace-team1", isDirectory: () => true } as never,
|
|
92
|
-
]);
|
|
93
|
-
vi.mocked(fs.stat).mockResolvedValue({} as never);
|
|
94
|
-
vi.mocked(fs.readFile).mockResolvedValue(
|
|
95
|
-
JSON.stringify({
|
|
96
|
-
entries: {
|
|
97
|
-
"recipe.lead": { installedCronId: "cron-1", orphaned: false },
|
|
98
|
-
},
|
|
99
|
-
})
|
|
100
|
-
);
|
|
101
|
-
vi.mocked(runOpenClaw).mockResolvedValue({
|
|
102
|
-
ok: true,
|
|
103
|
-
stdout: JSON.stringify([{ id: "agent1", workspace: "/ws/agent1" }]),
|
|
104
|
-
stderr: "",
|
|
105
|
-
exitCode: 0,
|
|
106
|
-
});
|
|
107
|
-
const result = await buildIdToScopeMap("/home/.openclaw/workspace");
|
|
108
|
-
expect(result.size).toBeGreaterThanOrEqual(0);
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
describe("markOrphanedInTeamWorkspaces", () => {
|
|
113
|
-
it("marks matching cron as orphaned", async () => {
|
|
114
|
-
vi.mocked(fs.readdir).mockResolvedValue([
|
|
115
|
-
{ name: "workspace-team1", isDirectory: () => true } as never,
|
|
116
|
-
]);
|
|
117
|
-
vi.mocked(fs.stat).mockResolvedValue({} as never);
|
|
118
|
-
vi.mocked(fs.readFile).mockResolvedValue(
|
|
119
|
-
JSON.stringify({
|
|
120
|
-
version: 1,
|
|
121
|
-
entries: {
|
|
122
|
-
"recipe.lead": { installedCronId: "cron-1", orphaned: false },
|
|
123
|
-
},
|
|
124
|
-
})
|
|
125
|
-
);
|
|
126
|
-
const result = await markOrphanedInTeamWorkspaces("cron-1", "/home/.openclaw/workspace");
|
|
127
|
-
expect(result.length).toBeGreaterThanOrEqual(0);
|
|
128
|
-
expect(fs.writeFile).toHaveBeenCalled();
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it("returns empty when no match", async () => {
|
|
132
|
-
vi.mocked(fs.readdir).mockResolvedValue([]);
|
|
133
|
-
const result = await markOrphanedInTeamWorkspaces("cron-99", "/home/.openclaw/workspace");
|
|
134
|
-
expect(result).toEqual([]);
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
describe("getBaseWorkspaceFromGateway", () => {
|
|
139
|
-
it("extracts workspace from gateway config", async () => {
|
|
140
|
-
const toolsInvoke = vi.fn().mockResolvedValue({
|
|
141
|
-
content: [
|
|
142
|
-
{
|
|
143
|
-
type: "text",
|
|
144
|
-
text: JSON.stringify({
|
|
145
|
-
result: {
|
|
146
|
-
raw: JSON.stringify({
|
|
147
|
-
agents: { defaults: { workspace: "/home/.openclaw/workspace" } },
|
|
148
|
-
}),
|
|
149
|
-
},
|
|
150
|
-
}),
|
|
151
|
-
},
|
|
152
|
-
],
|
|
153
|
-
});
|
|
154
|
-
const result = await getBaseWorkspaceFromGateway(toolsInvoke);
|
|
155
|
-
expect(result).toBe("/home/.openclaw/workspace");
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it("returns empty when no config", async () => {
|
|
159
|
-
const toolsInvoke = vi.fn().mockResolvedValue({ content: [] });
|
|
160
|
-
const result = await getBaseWorkspaceFromGateway(toolsInvoke);
|
|
161
|
-
expect(result).toBe("");
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
});
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
import { toolsInvoke } from "@/lib/gateway";
|
|
3
|
-
import { getBaseWorkspaceFromGateway, markOrphanedInTeamWorkspaces } from "../helpers";
|
|
4
|
-
|
|
5
|
-
export async function POST(req: Request) {
|
|
6
|
-
const body = (await req.json()) as { id?: string };
|
|
7
|
-
const id = String(body.id ?? "").trim();
|
|
8
|
-
if (!id) return NextResponse.json({ ok: false, error: "id is required" }, { status: 400 });
|
|
9
|
-
|
|
10
|
-
const result = await toolsInvoke({ tool: "cron", args: { action: "remove", jobId: id } });
|
|
11
|
-
|
|
12
|
-
let orphanedIn: Array<{ teamId: string; mappingPath: string; keys: string[] }> = [];
|
|
13
|
-
try {
|
|
14
|
-
const baseWorkspace = await getBaseWorkspaceFromGateway(toolsInvoke);
|
|
15
|
-
if (baseWorkspace) {
|
|
16
|
-
orphanedIn = await markOrphanedInTeamWorkspaces(id, baseWorkspace);
|
|
17
|
-
}
|
|
18
|
-
} catch {
|
|
19
|
-
// ignore
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return NextResponse.json({ ok: true, id, result, orphanedIn });
|
|
23
|
-
}
|
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { runOpenClaw } from "@/lib/openclaw";
|
|
4
|
-
|
|
5
|
-
export type CronScope = { kind: "team" | "agent"; id: string; label: string; href: string };
|
|
6
|
-
|
|
7
|
-
function hrefForScope(scope: { kind: "team" | "agent"; id: string }) {
|
|
8
|
-
return scope.kind === "team" ? `/teams/${encodeURIComponent(scope.id)}` : `/agents/${encodeURIComponent(scope.id)}`;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
type CronEntry = { installedCronId?: unknown; orphaned?: unknown };
|
|
12
|
-
|
|
13
|
-
function addEntriesToScopeMap(
|
|
14
|
-
entries: Record<string, CronEntry>,
|
|
15
|
-
scopeId: string,
|
|
16
|
-
kind: "team" | "agent",
|
|
17
|
-
idToScope: Map<string, CronScope>
|
|
18
|
-
): void {
|
|
19
|
-
for (const v of Object.values(entries)) {
|
|
20
|
-
if (v && !Boolean(v.orphaned)) {
|
|
21
|
-
const id = String(v.installedCronId ?? "").trim();
|
|
22
|
-
if (id) idToScope.set(id, { kind, id: scopeId, label: scopeId, href: hrefForScope({ kind, id: scopeId }) });
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async function collectAgentScopes(idToScope: Map<string, CronScope>): Promise<void> {
|
|
28
|
-
try {
|
|
29
|
-
const cfgText = await runOpenClaw(["config", "get", "agents.list", "--no-color"]);
|
|
30
|
-
if (!cfgText.ok) return;
|
|
31
|
-
const list = JSON.parse(String(cfgText.stdout ?? "[]")) as Array<{ id?: unknown; workspace?: unknown }>;
|
|
32
|
-
for (const a of list) {
|
|
33
|
-
const agentId = String(a.id ?? "");
|
|
34
|
-
const workspace = String(a.workspace ?? "");
|
|
35
|
-
if (!agentId || !workspace) continue;
|
|
36
|
-
const cronPath = path.join(workspace, "notes", "cron-jobs.json");
|
|
37
|
-
try {
|
|
38
|
-
const raw = await fs.readFile(cronPath, "utf8");
|
|
39
|
-
const json = JSON.parse(raw) as { entries?: Record<string, CronEntry> };
|
|
40
|
-
addEntriesToScopeMap(json.entries ?? {}, agentId, "agent", idToScope);
|
|
41
|
-
} catch {
|
|
42
|
-
// ignore
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
} catch {
|
|
46
|
-
// ignore
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export async function buildIdToScopeMap(baseWorkspace: string): Promise<Map<string, CronScope>> {
|
|
51
|
-
const idToScope = new Map<string, CronScope>();
|
|
52
|
-
const baseHome = path.resolve(baseWorkspace, "..");
|
|
53
|
-
const entries = await fs.readdir(baseHome, { withFileTypes: true });
|
|
54
|
-
|
|
55
|
-
for (const ent of entries) {
|
|
56
|
-
if (!ent.isDirectory() || !ent.name.startsWith("workspace-")) continue;
|
|
57
|
-
const scopeId = ent.name.replace(/^workspace-/, "");
|
|
58
|
-
const teamJsonPath = path.join(baseHome, ent.name, "team.json");
|
|
59
|
-
const teamNotesCronPath = path.join(baseHome, ent.name, "notes", "cron-jobs.json");
|
|
60
|
-
try {
|
|
61
|
-
await fs.stat(teamJsonPath);
|
|
62
|
-
} catch {
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
try {
|
|
66
|
-
const raw = await fs.readFile(teamNotesCronPath, "utf8");
|
|
67
|
-
const json = JSON.parse(raw) as { entries?: Record<string, CronEntry> };
|
|
68
|
-
addEntriesToScopeMap(json.entries ?? {}, scopeId, "team", idToScope);
|
|
69
|
-
} catch {
|
|
70
|
-
// ignore
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
await collectAgentScopes(idToScope);
|
|
75
|
-
return idToScope;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export async function getInstalledIdsForTeam(provenancePath: string): Promise<string[]> {
|
|
79
|
-
try {
|
|
80
|
-
const text = await fs.readFile(provenancePath, "utf8");
|
|
81
|
-
const json = JSON.parse(text) as { entries?: Record<string, { installedCronId?: unknown; orphaned?: unknown }> };
|
|
82
|
-
const entries = json.entries ?? {};
|
|
83
|
-
return Object.values(entries)
|
|
84
|
-
.filter((e) => !Boolean(e.orphaned))
|
|
85
|
-
.map((e) => String(e.installedCronId ?? "").trim())
|
|
86
|
-
.filter(Boolean);
|
|
87
|
-
} catch {
|
|
88
|
-
return [];
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export function enrichJobsWithScope(
|
|
93
|
-
jobs: unknown[],
|
|
94
|
-
idToScope: Map<string, CronScope>
|
|
95
|
-
): Array<unknown & { scope?: CronScope }> {
|
|
96
|
-
return jobs.map((j) => {
|
|
97
|
-
const id = String((j as { id?: unknown }).id ?? "");
|
|
98
|
-
const scope = id ? idToScope.get(id) : undefined;
|
|
99
|
-
return (scope ? { ...(j as object), scope } : j) as unknown & { scope?: CronScope };
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
type MappingStateV1 = {
|
|
104
|
-
version: 1;
|
|
105
|
-
entries: Record<string, { installedCronId: string; orphaned?: boolean }>;
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
async function markOrphanedInOneMapping(
|
|
109
|
-
id: string,
|
|
110
|
-
mappingPath: string,
|
|
111
|
-
teamId: string
|
|
112
|
-
): Promise<{ teamId: string; mappingPath: string; keys: string[] } | null> {
|
|
113
|
-
try {
|
|
114
|
-
const rawMapping = await fs.readFile(mappingPath, "utf8");
|
|
115
|
-
const mapping = JSON.parse(rawMapping) as MappingStateV1;
|
|
116
|
-
if (!mapping || mapping.version !== 1 || !mapping.entries) return null;
|
|
117
|
-
|
|
118
|
-
let changed = false;
|
|
119
|
-
const keys: string[] = [];
|
|
120
|
-
for (const [k, v] of Object.entries(mapping.entries)) {
|
|
121
|
-
if (String(v?.installedCronId ?? "").trim() === id && !v.orphaned) {
|
|
122
|
-
mapping.entries[k] = { ...v, orphaned: true };
|
|
123
|
-
changed = true;
|
|
124
|
-
keys.push(k);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
if (!changed) return null;
|
|
128
|
-
await fs.writeFile(mappingPath, JSON.stringify(mapping, null, 2) + "\n", "utf8");
|
|
129
|
-
return { teamId, mappingPath, keys };
|
|
130
|
-
} catch {
|
|
131
|
-
return null;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
export async function markOrphanedInTeamWorkspaces(
|
|
136
|
-
id: string,
|
|
137
|
-
baseWorkspace: string
|
|
138
|
-
): Promise<Array<{ teamId: string; mappingPath: string; keys: string[] }>> {
|
|
139
|
-
const orphanedIn: Array<{ teamId: string; mappingPath: string; keys: string[] }> = [];
|
|
140
|
-
const baseHome = path.resolve(baseWorkspace, "..");
|
|
141
|
-
const entries = await fs.readdir(baseHome, { withFileTypes: true });
|
|
142
|
-
|
|
143
|
-
for (const ent of entries) {
|
|
144
|
-
if (!ent.isDirectory() || !ent.name.startsWith("workspace-")) continue;
|
|
145
|
-
const teamId = ent.name.replace(/^workspace-/, "");
|
|
146
|
-
const teamJsonPath = path.join(baseHome, ent.name, "team.json");
|
|
147
|
-
const mappingPath = path.join(baseHome, ent.name, "notes", "cron-jobs.json");
|
|
148
|
-
try {
|
|
149
|
-
await fs.stat(teamJsonPath);
|
|
150
|
-
} catch {
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
const result = await markOrphanedInOneMapping(id, mappingPath, teamId);
|
|
154
|
-
if (result) orphanedIn.push(result);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return orphanedIn;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
export async function getBaseWorkspaceFromGateway(
|
|
161
|
-
toolsInvoke: (opts: { tool: string; args?: Record<string, unknown> }) => Promise<unknown>
|
|
162
|
-
): Promise<string> {
|
|
163
|
-
const cfg = (await toolsInvoke({
|
|
164
|
-
tool: "gateway",
|
|
165
|
-
args: { action: "config.get", raw: "{}" },
|
|
166
|
-
})) as { content?: Array<{ type: string; text?: string }> };
|
|
167
|
-
const cfgText = cfg?.content?.find((c) => c.type === "text")?.text ?? "";
|
|
168
|
-
const env = cfgText ? (JSON.parse(cfgText) as { result?: { raw?: string } }) : null;
|
|
169
|
-
const raw = String(env?.result?.raw ?? "");
|
|
170
|
-
const parsedRaw = raw ? (JSON.parse(raw) as { agents?: { defaults?: { workspace?: string } } }) : null;
|
|
171
|
-
return String(parsedRaw?.agents?.defaults?.workspace ?? "").trim();
|
|
172
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
import { toolsInvoke } from "@/lib/gateway";
|
|
3
|
-
|
|
4
|
-
export async function POST(req: Request) {
|
|
5
|
-
const body = (await req.json()) as { id?: string; action?: string };
|
|
6
|
-
const id = String(body.id ?? "").trim();
|
|
7
|
-
const action = String(body.action ?? "").trim();
|
|
8
|
-
|
|
9
|
-
if (!id) return NextResponse.json({ ok: false, error: "id is required" }, { status: 400 });
|
|
10
|
-
if (!["enable", "disable", "run"].includes(action)) {
|
|
11
|
-
return NextResponse.json({ ok: false, error: "action must be enable|disable|run" }, { status: 400 });
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
if (action === "run") {
|
|
15
|
-
const result = await toolsInvoke({ tool: "cron", args: { action: "run", jobId: id } });
|
|
16
|
-
return NextResponse.json({ ok: true, action, id, result });
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const patch = { enabled: action === "enable" };
|
|
20
|
-
const result = await toolsInvoke({ tool: "cron", args: { action: "update", jobId: id, patch } });
|
|
21
|
-
return NextResponse.json({ ok: true, action, id, result });
|
|
22
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { NextResponse } from "next/server";
|
|
3
|
-
import { toolsInvoke } from "@/lib/gateway";
|
|
4
|
-
import { readOpenClawConfig, getTeamWorkspaceDir } from "@/lib/paths";
|
|
5
|
-
import { errorMessage } from "@/lib/errors";
|
|
6
|
-
import { buildIdToScopeMap, getInstalledIdsForTeam, enrichJobsWithScope } from "../helpers";
|
|
7
|
-
|
|
8
|
-
type CronToolResult = { content: Array<{ type: string; text?: string }> };
|
|
9
|
-
|
|
10
|
-
export async function GET(req: Request) {
|
|
11
|
-
try {
|
|
12
|
-
const url = new URL(req.url);
|
|
13
|
-
const teamId = String(url.searchParams.get("teamId") ?? "").trim();
|
|
14
|
-
|
|
15
|
-
const result = await toolsInvoke<CronToolResult>({
|
|
16
|
-
tool: "cron",
|
|
17
|
-
args: { action: "list", includeDisabled: true },
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
// Tool responses may come back as either:
|
|
21
|
-
// - {type:"text", text:"{...}"} (stringified JSON)
|
|
22
|
-
// - {type:"json", json:{...}} (already-parsed)
|
|
23
|
-
const text = result?.content?.find((c) => c.type === "text")?.text;
|
|
24
|
-
const jsonPayload = (result?.content as Array<{ type: string; text?: string; json?: unknown }> | undefined)?.find(
|
|
25
|
-
(c) => c.type === "json" && c.json,
|
|
26
|
-
)?.json;
|
|
27
|
-
|
|
28
|
-
const parsed = ((): { jobs?: unknown[] } => {
|
|
29
|
-
if (jsonPayload && typeof jsonPayload === "object") return jsonPayload as { jobs?: unknown[] };
|
|
30
|
-
if (text && text.trim()) return JSON.parse(text) as { jobs?: unknown[] };
|
|
31
|
-
return { jobs: [] };
|
|
32
|
-
})();
|
|
33
|
-
|
|
34
|
-
const jobs = Array.isArray(parsed.jobs) ? parsed.jobs : [];
|
|
35
|
-
|
|
36
|
-
const baseWorkspace = String((await readOpenClawConfig()).agents?.defaults?.workspace ?? "").trim();
|
|
37
|
-
const idToScope = baseWorkspace ? await buildIdToScopeMap(baseWorkspace) : new Map();
|
|
38
|
-
const enriched = enrichJobsWithScope(jobs, idToScope);
|
|
39
|
-
|
|
40
|
-
if (!teamId) return NextResponse.json({ ok: true, jobs: enriched });
|
|
41
|
-
|
|
42
|
-
const teamDir = await getTeamWorkspaceDir(teamId);
|
|
43
|
-
const provenancePath = path.join(teamDir, "notes", "cron-jobs.json");
|
|
44
|
-
const installedIds = await getInstalledIdsForTeam(provenancePath);
|
|
45
|
-
const filtered = enriched.filter((j) => installedIds.includes(String((j as { id?: unknown }).id ?? "")));
|
|
46
|
-
|
|
47
|
-
return NextResponse.json({ ok: true, jobs: filtered, teamId, provenancePath, installedIds });
|
|
48
|
-
} catch (e: unknown) {
|
|
49
|
-
const msg = errorMessage(e);
|
|
50
|
-
return NextResponse.json({ ok: false, error: msg }, { status: 500 });
|
|
51
|
-
}
|
|
52
|
-
}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { NextResponse } from "next/server";
|
|
4
|
-
import { cronJobId, type CronJobShape } from "@/lib/cron";
|
|
5
|
-
import { getContentText, toolsInvoke } from "@/lib/gateway";
|
|
6
|
-
import { teamDirFromBaseWorkspace } from "@/lib/paths";
|
|
7
|
-
|
|
8
|
-
type MappingStateV1 = {
|
|
9
|
-
version: 1;
|
|
10
|
-
entries: Record<string, { installedCronId: string; orphaned?: boolean }>;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
async function readJson<T>(p: string): Promise<T> {
|
|
14
|
-
const raw = await fs.readFile(p, "utf8");
|
|
15
|
-
return JSON.parse(raw) as T;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export async function GET(req: Request) {
|
|
19
|
-
const url = new URL(req.url);
|
|
20
|
-
const teamId = String(url.searchParams.get("teamId") ?? "").trim();
|
|
21
|
-
if (!teamId) {
|
|
22
|
-
return NextResponse.json({ ok: false, error: "teamId is required" }, { status: 400 });
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Team workspace root is a sibling of agents.defaults.workspace: ~/.openclaw/workspace-<teamId>
|
|
26
|
-
const result = await toolsInvoke<{ content: Array<{ type: string; text?: string }> }>({
|
|
27
|
-
tool: "gateway",
|
|
28
|
-
args: { action: "config.get", raw: "{}" },
|
|
29
|
-
});
|
|
30
|
-
const cfgText = getContentText(result?.content) ?? "";
|
|
31
|
-
if (!cfgText) {
|
|
32
|
-
return NextResponse.json({ ok: false, error: "Failed to fetch config via gateway" }, { status: 500 });
|
|
33
|
-
}
|
|
34
|
-
const env = JSON.parse(cfgText) as { result?: { raw?: string } };
|
|
35
|
-
const raw = String(env.result?.raw ?? "");
|
|
36
|
-
const parsedRaw = raw ? (JSON.parse(raw) as { agents?: { defaults?: { workspace?: string } } }) : null;
|
|
37
|
-
const baseWorkspace = String(parsedRaw?.agents?.defaults?.workspace ?? "").trim();
|
|
38
|
-
if (!baseWorkspace) {
|
|
39
|
-
return NextResponse.json({ ok: false, error: "agents.defaults.workspace not set" }, { status: 500 });
|
|
40
|
-
}
|
|
41
|
-
const teamDir = teamDirFromBaseWorkspace(baseWorkspace, teamId);
|
|
42
|
-
const mappingPath = path.join(teamDir, "notes", "cron-jobs.json");
|
|
43
|
-
|
|
44
|
-
let mapping: MappingStateV1 | null = null;
|
|
45
|
-
try {
|
|
46
|
-
mapping = await readJson<MappingStateV1>(mappingPath);
|
|
47
|
-
} catch {
|
|
48
|
-
// no mapping (yet)
|
|
49
|
-
mapping = null;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const ids = new Set(
|
|
53
|
-
Object.values(mapping?.entries ?? {})
|
|
54
|
-
.filter((e) => e && typeof e.installedCronId === "string" && !e.orphaned)
|
|
55
|
-
.map((e) => e.installedCronId)
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
const parsed = (await toolsInvoke<{ jobs: unknown[] }>({
|
|
59
|
-
tool: "cron",
|
|
60
|
-
args: { action: "list", includeDisabled: true },
|
|
61
|
-
})) as { jobs: unknown[] };
|
|
62
|
-
const jobs = (parsed.jobs ?? []).filter((j) => ids.has(cronJobId(j as CronJobShape)));
|
|
63
|
-
|
|
64
|
-
return NextResponse.json({ ok: true, teamId, teamDir, mappingPath, jobCount: jobs.length, jobs });
|
|
65
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
import { errorMessage } from "@/lib/errors";
|
|
3
|
-
import { runOpenClaw } from "@/lib/openclaw";
|
|
4
|
-
|
|
5
|
-
export async function POST() {
|
|
6
|
-
try {
|
|
7
|
-
// NOTE: Kitchen runs inside the OpenClaw gateway process.
|
|
8
|
-
// If we synchronously restart the gateway while holding an HTTP request open, the browser
|
|
9
|
-
// can see a client-side exception / aborted fetch.
|
|
10
|
-
//
|
|
11
|
-
// Schedule the restart and respond immediately.
|
|
12
|
-
setTimeout(() => {
|
|
13
|
-
void runOpenClaw(["gateway", "restart"]);
|
|
14
|
-
}, 50);
|
|
15
|
-
|
|
16
|
-
return NextResponse.json({ ok: true, scheduled: true });
|
|
17
|
-
} catch (e: unknown) {
|
|
18
|
-
return NextResponse.json({ ok: false, error: errorMessage(e) }, { status: 500 });
|
|
19
|
-
}
|
|
20
|
-
}
|