@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,91 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { useEffect, useState } from "react";
|
|
4
|
-
import { errorMessage } from "@/lib/errors";
|
|
5
|
-
import { fetchJson } from "@/lib/fetch-json";
|
|
6
|
-
|
|
7
|
-
type Mode = "off" | "prompt" | "on";
|
|
8
|
-
|
|
9
|
-
export default function SettingsClient() {
|
|
10
|
-
const [loading, setLoading] = useState(true);
|
|
11
|
-
const [saving, setSaving] = useState(false);
|
|
12
|
-
const [mode, setMode] = useState<Mode>("prompt");
|
|
13
|
-
const [msg, setMsg] = useState<string>("");
|
|
14
|
-
|
|
15
|
-
useEffect(() => {
|
|
16
|
-
(async () => {
|
|
17
|
-
setLoading(true);
|
|
18
|
-
setMsg("");
|
|
19
|
-
try {
|
|
20
|
-
const json = await fetchJson<{ ok?: boolean; value?: string; error?: string }>(
|
|
21
|
-
"/api/settings/cron-installation",
|
|
22
|
-
{ cache: "no-store" }
|
|
23
|
-
);
|
|
24
|
-
if (!json.ok) throw new Error(json.error || "Failed to load config");
|
|
25
|
-
const v = String(json.value || "").trim();
|
|
26
|
-
if (v === "off" || v === "prompt" || v === "on") setMode(v);
|
|
27
|
-
else setMode("prompt");
|
|
28
|
-
} catch (e: unknown) {
|
|
29
|
-
setMsg(errorMessage(e));
|
|
30
|
-
} finally {
|
|
31
|
-
setLoading(false);
|
|
32
|
-
}
|
|
33
|
-
})();
|
|
34
|
-
}, []);
|
|
35
|
-
|
|
36
|
-
async function save(next: Mode) {
|
|
37
|
-
setSaving(true);
|
|
38
|
-
setMsg("");
|
|
39
|
-
try {
|
|
40
|
-
const json = await fetchJson<{ ok?: boolean; error?: string }>("/api/settings/cron-installation", {
|
|
41
|
-
method: "PUT",
|
|
42
|
-
headers: { "content-type": "application/json" },
|
|
43
|
-
body: JSON.stringify({ value: next }),
|
|
44
|
-
});
|
|
45
|
-
if (!json.ok) throw new Error(json.error || "Save failed");
|
|
46
|
-
setMode(next);
|
|
47
|
-
setMsg("Saved.");
|
|
48
|
-
} catch (e: unknown) {
|
|
49
|
-
setMsg(errorMessage(e));
|
|
50
|
-
} finally {
|
|
51
|
-
setSaving(false);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const Option = ({ value, title, help }: { value: Mode; title: string; help: string }) => (
|
|
56
|
-
<button
|
|
57
|
-
type="button"
|
|
58
|
-
onClick={() => save(value)}
|
|
59
|
-
disabled={loading || saving}
|
|
60
|
-
className={`ck-glass w-full text-left px-4 py-3 transition-colors hover:bg-white/10 ${
|
|
61
|
-
mode === value ? "border-[color:var(--ck-accent-red)]" : ""
|
|
62
|
-
}`}
|
|
63
|
-
>
|
|
64
|
-
<div className="flex items-baseline justify-between gap-3">
|
|
65
|
-
<div className="font-medium">{title}</div>
|
|
66
|
-
{mode === value ? (
|
|
67
|
-
<div className="text-xs font-medium text-[color:var(--ck-accent-red)]">Selected</div>
|
|
68
|
-
) : null}
|
|
69
|
-
</div>
|
|
70
|
-
<div className="mt-1 text-sm text-[color:var(--ck-text-secondary)]">{help}</div>
|
|
71
|
-
</button>
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
return (
|
|
75
|
-
<div className="space-y-3">
|
|
76
|
-
<Option value="off" title="Off" help="Never install or reconcile recipe-defined cron jobs." />
|
|
77
|
-
<Option
|
|
78
|
-
value="prompt"
|
|
79
|
-
title="Prompt (default)"
|
|
80
|
-
help="Ask at scaffold time. Default answer should be No; jobs are installed disabled unless you opt in."
|
|
81
|
-
/>
|
|
82
|
-
<Option value="on" title="On" help="Install/reconcile jobs during scaffold (enabledByDefault controls new jobs)." />
|
|
83
|
-
|
|
84
|
-
{msg ? (
|
|
85
|
-
<div className="mt-2 rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/20 p-3 text-sm">
|
|
86
|
-
{msg}
|
|
87
|
-
</div>
|
|
88
|
-
) : null}
|
|
89
|
-
</div>
|
|
90
|
-
);
|
|
91
|
-
}
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { useMemo, useState } from "react";
|
|
4
|
-
import { ConfirmationModal } from "@/components/ConfirmationModal";
|
|
5
|
-
import type { RecipeListItem } from "@/lib/recipes";
|
|
6
|
-
import { slugifyId } from "@/lib/slugify";
|
|
7
|
-
|
|
8
|
-
function getIdInputClass(state: "empty" | "available" | "taken"): string {
|
|
9
|
-
const base = "mt-1 w-full rounded-[var(--ck-radius-sm)] border bg-black/25 px-3 py-2 text-sm text-[color:var(--ck-text-primary)] ";
|
|
10
|
-
if (state === "available") return base + "border-emerald-400/50";
|
|
11
|
-
if (state === "taken") return base + "border-red-400/60";
|
|
12
|
-
return base + "border-white/10";
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function CloneTeamModal({
|
|
16
|
-
open,
|
|
17
|
-
onClose,
|
|
18
|
-
recipes,
|
|
19
|
-
onConfirm,
|
|
20
|
-
}: {
|
|
21
|
-
open: boolean;
|
|
22
|
-
onClose: () => void;
|
|
23
|
-
recipes: RecipeListItem[];
|
|
24
|
-
onConfirm: (args: { id: string; name: string; scaffold: boolean }) => void;
|
|
25
|
-
}) {
|
|
26
|
-
const [name, setName] = useState("");
|
|
27
|
-
const [id, setId] = useState("");
|
|
28
|
-
const [idTouched, setIdTouched] = useState(false);
|
|
29
|
-
const [scaffold, setScaffold] = useState(true);
|
|
30
|
-
|
|
31
|
-
const derivedId = useMemo(() => slugifyId(name, 80), [name]);
|
|
32
|
-
const effectiveId = idTouched ? id : derivedId;
|
|
33
|
-
|
|
34
|
-
const availability = useMemo(() => {
|
|
35
|
-
const v = effectiveId.trim();
|
|
36
|
-
if (!v) return { state: "empty" as const, exists: false };
|
|
37
|
-
const exists = recipes.some((r) => r.id === v);
|
|
38
|
-
return { state: exists ? ("taken" as const) : ("available" as const), exists };
|
|
39
|
-
}, [effectiveId, recipes]);
|
|
40
|
-
|
|
41
|
-
const canConfirm = !!name.trim() && !!effectiveId.trim() && availability.state !== "taken";
|
|
42
|
-
|
|
43
|
-
return (
|
|
44
|
-
<ConfirmationModal
|
|
45
|
-
open={open}
|
|
46
|
-
onClose={onClose}
|
|
47
|
-
title="Clone Team"
|
|
48
|
-
confirmLabel="Clone"
|
|
49
|
-
onConfirm={() => onConfirm({ id: effectiveId.trim(), name: name.trim(), scaffold })}
|
|
50
|
-
confirmDisabled={!canConfirm}
|
|
51
|
-
>
|
|
52
|
-
<p className="mt-1 text-sm text-[color:var(--ck-text-secondary)]">
|
|
53
|
-
Enter a new team name and id. The id will be used as the new custom recipe id.
|
|
54
|
-
</p>
|
|
55
|
-
|
|
56
|
-
<label className="mt-4 block text-xs font-medium text-[color:var(--ck-text-secondary)]">New team name</label>
|
|
57
|
-
<input
|
|
58
|
-
value={name}
|
|
59
|
-
onChange={(e) => setName(e.target.value)}
|
|
60
|
-
className="mt-1 w-full rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/25 px-3 py-2 text-sm text-[color:var(--ck-text-primary)]"
|
|
61
|
-
/>
|
|
62
|
-
|
|
63
|
-
<label className="mt-4 block text-xs font-medium text-[color:var(--ck-text-secondary)]">New team id</label>
|
|
64
|
-
<input
|
|
65
|
-
value={effectiveId}
|
|
66
|
-
onChange={(e) => {
|
|
67
|
-
setIdTouched(true);
|
|
68
|
-
setId(e.target.value);
|
|
69
|
-
}}
|
|
70
|
-
className={getIdInputClass(availability.state)}
|
|
71
|
-
/>
|
|
72
|
-
<div className="mt-1 text-xs text-[color:var(--ck-text-tertiary)]">
|
|
73
|
-
{availability.state === "taken" && "That id is already taken."}
|
|
74
|
-
{availability.state === "available" && "Id is available."}
|
|
75
|
-
</div>
|
|
76
|
-
|
|
77
|
-
{availability.state === "taken" ? (
|
|
78
|
-
<div className="mt-3 rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/20 p-3">
|
|
79
|
-
<div className="text-xs font-medium text-[color:var(--ck-text-secondary)]">Try one of these ids</div>
|
|
80
|
-
<div className="mt-2 flex flex-wrap gap-2">
|
|
81
|
-
{[`custom-${effectiveId.trim()}`, `my-${effectiveId.trim()}`, `${effectiveId.trim()}-2`, `${effectiveId.trim()}-alt`]
|
|
82
|
-
.filter((x) => x && x !== effectiveId.trim())
|
|
83
|
-
.map((x) => (
|
|
84
|
-
<button
|
|
85
|
-
key={x}
|
|
86
|
-
type="button"
|
|
87
|
-
onClick={() => {
|
|
88
|
-
setIdTouched(true);
|
|
89
|
-
setId(x);
|
|
90
|
-
}}
|
|
91
|
-
className="rounded-[var(--ck-radius-sm)] border border-white/10 bg-white/5 px-2.5 py-1.5 text-xs font-medium text-[color:var(--ck-text-primary)] hover:bg-white/10"
|
|
92
|
-
>
|
|
93
|
-
{x}
|
|
94
|
-
</button>
|
|
95
|
-
))}
|
|
96
|
-
</div>
|
|
97
|
-
</div>
|
|
98
|
-
) : null}
|
|
99
|
-
|
|
100
|
-
<label className="mt-5 flex items-start gap-2 rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/20 p-3 text-sm text-[color:var(--ck-text-secondary)]">
|
|
101
|
-
<input
|
|
102
|
-
type="checkbox"
|
|
103
|
-
checked={scaffold}
|
|
104
|
-
onChange={(e) => setScaffold(e.target.checked)}
|
|
105
|
-
className="mt-1"
|
|
106
|
-
/>
|
|
107
|
-
<span>
|
|
108
|
-
Also scaffold workspace files (recommended).<br />
|
|
109
|
-
<span className="text-xs text-[color:var(--ck-text-tertiary)]">
|
|
110
|
-
Creates the team workspace + standard file tree immediately so the cloned team is usable.
|
|
111
|
-
</span>
|
|
112
|
-
</span>
|
|
113
|
-
</label>
|
|
114
|
-
</ConfirmationModal>
|
|
115
|
-
);
|
|
116
|
-
}
|
|
@@ -1,255 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { useCallback, useEffect, useState } from "react";
|
|
4
|
-
|
|
5
|
-
import { fetchJson } from "@/lib/fetch-json";
|
|
6
|
-
import { OrchestratorSetupModal } from "./OrchestratorSetupModal";
|
|
7
|
-
|
|
8
|
-
type OrchestratorState =
|
|
9
|
-
| {
|
|
10
|
-
ok: true;
|
|
11
|
-
teamId: string;
|
|
12
|
-
present: false;
|
|
13
|
-
reason?: string;
|
|
14
|
-
}
|
|
15
|
-
| {
|
|
16
|
-
ok: true;
|
|
17
|
-
teamId: string;
|
|
18
|
-
present: true;
|
|
19
|
-
agent: { id: string; identityName?: string; workspace: string };
|
|
20
|
-
tmuxSessions: Array<{ name: string; attached: boolean; windows?: number; created?: string }>;
|
|
21
|
-
worktrees: Array<{ path: string; branch?: string; sha?: string }>;
|
|
22
|
-
activeTasksSummary: null | { path: string; taskCount?: number; rawType?: string };
|
|
23
|
-
settingsPaths: string[];
|
|
24
|
-
}
|
|
25
|
-
| {
|
|
26
|
-
ok: false;
|
|
27
|
-
error: string;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export function OrchestratorPanel({ teamId }: { teamId: string }) {
|
|
31
|
-
const [loading, setLoading] = useState(true);
|
|
32
|
-
const [state, setState] = useState<OrchestratorState | null>(null);
|
|
33
|
-
const [lastLoadedAt, setLastLoadedAt] = useState<string | null>(null);
|
|
34
|
-
const [setupOpen, setSetupOpen] = useState(false);
|
|
35
|
-
|
|
36
|
-
const load = useCallback(async () => {
|
|
37
|
-
setLoading(true);
|
|
38
|
-
try {
|
|
39
|
-
const json = await fetchJson<OrchestratorState>(
|
|
40
|
-
`/api/teams/orchestrator?teamId=${encodeURIComponent(teamId)}`,
|
|
41
|
-
{ cache: "no-store" }
|
|
42
|
-
);
|
|
43
|
-
setState(json);
|
|
44
|
-
setLastLoadedAt(new Date().toISOString());
|
|
45
|
-
} catch (e: unknown) {
|
|
46
|
-
setState({ ok: false, error: e instanceof Error ? e.message : String(e) });
|
|
47
|
-
setLastLoadedAt(new Date().toISOString());
|
|
48
|
-
} finally {
|
|
49
|
-
setLoading(false);
|
|
50
|
-
}
|
|
51
|
-
}, [teamId]);
|
|
52
|
-
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
void load();
|
|
55
|
-
}, [load]);
|
|
56
|
-
|
|
57
|
-
if (loading) {
|
|
58
|
-
return <div className="mt-6 ck-glass-strong p-4">Loading orchestrator state…</div>;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (!state) {
|
|
62
|
-
return <div className="mt-6 ck-glass-strong p-4">No orchestrator state available.</div>;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (!state.ok) {
|
|
66
|
-
return (
|
|
67
|
-
<div className="mt-6 ck-glass-strong p-4">
|
|
68
|
-
<div className="text-sm font-medium text-[color:var(--ck-text-primary)]">Orchestrator</div>
|
|
69
|
-
<div className="mt-3 rounded-[var(--ck-radius-sm)] border border-red-400/30 bg-red-500/10 p-3 text-sm text-red-100">
|
|
70
|
-
{state.error}
|
|
71
|
-
</div>
|
|
72
|
-
</div>
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (!state.present) {
|
|
77
|
-
return (
|
|
78
|
-
<div className="mt-6 ck-glass-strong p-4">
|
|
79
|
-
<div className="flex flex-wrap items-start justify-between gap-3">
|
|
80
|
-
<div>
|
|
81
|
-
<div className="text-sm font-medium text-[color:var(--ck-text-primary)]">Orchestrator</div>
|
|
82
|
-
<p className="mt-2 text-sm text-[color:var(--ck-text-secondary)]">No swarm/orchestrator detected for this team.</p>
|
|
83
|
-
</div>
|
|
84
|
-
<button
|
|
85
|
-
type="button"
|
|
86
|
-
onClick={() => setSetupOpen(true)}
|
|
87
|
-
className="rounded-[var(--ck-radius-sm)] bg-[var(--ck-accent-red)] px-3 py-2 text-sm font-medium text-white shadow-[var(--ck-shadow-1)] hover:bg-[var(--ck-accent-red-hover)]"
|
|
88
|
-
>
|
|
89
|
-
Add Orchestrator
|
|
90
|
-
</button>
|
|
91
|
-
</div>
|
|
92
|
-
|
|
93
|
-
<div className="mt-3 rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/20 p-3 text-sm text-[color:var(--ck-text-secondary)]">
|
|
94
|
-
<div className="text-xs font-medium text-[color:var(--ck-text-tertiary)]">Detection</div>
|
|
95
|
-
<div className="mt-1 font-mono text-xs">{state.reason || "(no reason provided)"}</div>
|
|
96
|
-
</div>
|
|
97
|
-
|
|
98
|
-
<p className="mt-3 text-sm text-[color:var(--ck-text-secondary)]">
|
|
99
|
-
Default convention is <code><teamId>-swarm-orchestrator</code>. Once installed, this tab will show: tmux sessions,
|
|
100
|
-
git worktrees/branches, and active task state.
|
|
101
|
-
</p>
|
|
102
|
-
|
|
103
|
-
<OrchestratorSetupModal
|
|
104
|
-
open={setupOpen}
|
|
105
|
-
onClose={() => setSetupOpen(false)}
|
|
106
|
-
teamId={teamId}
|
|
107
|
-
onInstalled={() => {
|
|
108
|
-
setSetupOpen(false);
|
|
109
|
-
void load();
|
|
110
|
-
}}
|
|
111
|
-
/>
|
|
112
|
-
</div>
|
|
113
|
-
);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return (
|
|
117
|
-
<div className="mt-6 ck-glass-strong p-4">
|
|
118
|
-
<div className="flex flex-wrap items-start justify-between gap-3">
|
|
119
|
-
<div>
|
|
120
|
-
<div className="text-sm font-medium text-[color:var(--ck-text-primary)]">Orchestrator</div>
|
|
121
|
-
<div className="mt-1 text-xs text-[color:var(--ck-text-secondary)]">
|
|
122
|
-
Agent: <span className="font-mono">{state.agent.id}</span>
|
|
123
|
-
{state.agent.identityName ? ` (${state.agent.identityName})` : ""}
|
|
124
|
-
</div>
|
|
125
|
-
<div className="mt-1 text-xs text-[color:var(--ck-text-secondary)]">
|
|
126
|
-
Workspace: <span className="font-mono">{state.agent.workspace}</span>
|
|
127
|
-
</div>
|
|
128
|
-
</div>
|
|
129
|
-
|
|
130
|
-
<div className="flex items-center gap-3">
|
|
131
|
-
<div className="text-xs text-[color:var(--ck-text-tertiary)]">
|
|
132
|
-
{lastLoadedAt ? (
|
|
133
|
-
<span>
|
|
134
|
-
Last updated: <span className="font-mono">{lastLoadedAt}</span>
|
|
135
|
-
</span>
|
|
136
|
-
) : null}
|
|
137
|
-
</div>
|
|
138
|
-
<button
|
|
139
|
-
type="button"
|
|
140
|
-
onClick={() => void load()}
|
|
141
|
-
disabled={loading}
|
|
142
|
-
className="rounded-[var(--ck-radius-sm)] border border-white/10 bg-white/5 px-3 py-2 text-sm font-medium text-[color:var(--ck-text-primary)] shadow-[var(--ck-shadow-1)] transition-colors hover:bg-white/10 active:bg-white/15 disabled:opacity-50"
|
|
143
|
-
>
|
|
144
|
-
{loading ? "Refreshing…" : "Refresh"}
|
|
145
|
-
</button>
|
|
146
|
-
</div>
|
|
147
|
-
</div>
|
|
148
|
-
|
|
149
|
-
<div className="mt-5 grid grid-cols-1 gap-4 lg:grid-cols-2">
|
|
150
|
-
<section className="rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/20 p-3">
|
|
151
|
-
<div className="text-sm font-medium text-[color:var(--ck-text-primary)]">tmux sessions</div>
|
|
152
|
-
{state.tmuxSessions.length ? (
|
|
153
|
-
<ul className="mt-2 space-y-2">
|
|
154
|
-
{state.tmuxSessions.map((s) => (
|
|
155
|
-
<li key={s.name} className="text-sm text-[color:var(--ck-text-secondary)]">
|
|
156
|
-
<span className="font-mono">{s.name}</span>
|
|
157
|
-
<span className="ml-2 text-xs text-[color:var(--ck-text-tertiary)]">
|
|
158
|
-
attached={String(s.attached)}
|
|
159
|
-
{typeof s.windows === "number" ? ` windows=${s.windows}` : ""}
|
|
160
|
-
</span>
|
|
161
|
-
</li>
|
|
162
|
-
))}
|
|
163
|
-
</ul>
|
|
164
|
-
) : (
|
|
165
|
-
<div className="mt-2 text-sm text-[color:var(--ck-text-secondary)]">No sessions detected (or tmux not running).</div>
|
|
166
|
-
)}
|
|
167
|
-
</section>
|
|
168
|
-
|
|
169
|
-
<section className="rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/20 p-3">
|
|
170
|
-
<div className="text-sm font-medium text-[color:var(--ck-text-primary)]">git worktrees</div>
|
|
171
|
-
{state.worktrees.length ? (
|
|
172
|
-
<ul className="mt-2 space-y-2">
|
|
173
|
-
{state.worktrees.map((w) => (
|
|
174
|
-
<li key={w.path} className="text-sm text-[color:var(--ck-text-secondary)]">
|
|
175
|
-
<div className="font-mono text-xs">{w.path}</div>
|
|
176
|
-
<div className="text-xs text-[color:var(--ck-text-tertiary)]">
|
|
177
|
-
{w.branch ? w.branch : "(no branch)"}
|
|
178
|
-
{w.sha ? ` @ ${w.sha.slice(0, 7)}` : ""}
|
|
179
|
-
</div>
|
|
180
|
-
</li>
|
|
181
|
-
))}
|
|
182
|
-
</ul>
|
|
183
|
-
) : (
|
|
184
|
-
<div className="mt-2 text-sm text-[color:var(--ck-text-secondary)]">No worktrees detected.</div>
|
|
185
|
-
)}
|
|
186
|
-
</section>
|
|
187
|
-
</div>
|
|
188
|
-
|
|
189
|
-
<section className="mt-4 rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/20 p-3">
|
|
190
|
-
<div className="text-sm font-medium text-[color:var(--ck-text-primary)]">Active tasks</div>
|
|
191
|
-
{state.activeTasksSummary ? (
|
|
192
|
-
<div className="mt-2 text-sm text-[color:var(--ck-text-secondary)]">
|
|
193
|
-
<div className="font-mono text-xs">{state.activeTasksSummary.path}</div>
|
|
194
|
-
<div className="mt-1 text-xs text-[color:var(--ck-text-tertiary)]">
|
|
195
|
-
{typeof state.activeTasksSummary.taskCount === "number" ? `tasks=${state.activeTasksSummary.taskCount}` : "tasks=?"}
|
|
196
|
-
{state.activeTasksSummary.rawType ? ` type=${state.activeTasksSummary.rawType}` : ""}
|
|
197
|
-
</div>
|
|
198
|
-
</div>
|
|
199
|
-
) : (
|
|
200
|
-
<div className="mt-2 text-sm text-[color:var(--ck-text-secondary)]">No active-tasks.json found.</div>
|
|
201
|
-
)}
|
|
202
|
-
</section>
|
|
203
|
-
|
|
204
|
-
<section className="mt-4 rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/20 p-3">
|
|
205
|
-
<div className="text-sm font-medium text-[color:var(--ck-text-primary)]">CLI quick actions</div>
|
|
206
|
-
<p className="mt-2 text-sm text-[color:var(--ck-text-secondary)]">
|
|
207
|
-
The orchestrator is designed to be driven from the CLI (and usually tmux). Common commands:
|
|
208
|
-
</p>
|
|
209
|
-
<ul className="mt-2 list-disc space-y-1 pl-5 text-sm text-[color:var(--ck-text-secondary)]">
|
|
210
|
-
<li>
|
|
211
|
-
<span className="font-mono text-xs">tmux ls</span>
|
|
212
|
-
<span className="ml-2 text-xs text-[color:var(--ck-text-tertiary)]">(list sessions)</span>
|
|
213
|
-
</li>
|
|
214
|
-
<li>
|
|
215
|
-
<span className="font-mono text-xs">tmux attach -t <session></span>
|
|
216
|
-
<span className="ml-2 text-xs text-[color:var(--ck-text-tertiary)]">(jump into a running swarm)</span>
|
|
217
|
-
</li>
|
|
218
|
-
<li>
|
|
219
|
-
<span className="font-mono text-xs">git -C {state.agent.workspace} worktree list</span>
|
|
220
|
-
<span className="ml-2 text-xs text-[color:var(--ck-text-tertiary)]">(inspect worktrees)</span>
|
|
221
|
-
</li>
|
|
222
|
-
</ul>
|
|
223
|
-
<p className="mt-3 text-xs text-[color:var(--ck-text-tertiary)]">
|
|
224
|
-
Note: ClawKitchen is read-only here; it surfaces status and pointers, but does not run or attach to tmux.
|
|
225
|
-
</p>
|
|
226
|
-
</section>
|
|
227
|
-
|
|
228
|
-
<section className="mt-4 rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/20 p-3">
|
|
229
|
-
<div className="text-sm font-medium text-[color:var(--ck-text-primary)]">Human approval gate (recommended)</div>
|
|
230
|
-
<p className="mt-2 text-sm text-[color:var(--ck-text-secondary)]">
|
|
231
|
-
For workflows that publish, deploy, or send outbound messages, keep a <strong>human approval step</strong>.
|
|
232
|
-
</p>
|
|
233
|
-
<ul className="mt-2 list-disc space-y-1 pl-5 text-sm text-[color:var(--ck-text-secondary)]">
|
|
234
|
-
<li>Generate a proposed change/post as a draft.</li>
|
|
235
|
-
<li>Send the draft to a bound messaging channel (e.g. Telegram) for approval.</li>
|
|
236
|
-
<li>Only execute the final action after explicit approve/deny.</li>
|
|
237
|
-
</ul>
|
|
238
|
-
</section>
|
|
239
|
-
|
|
240
|
-
<section className="mt-4 rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/20 p-3">
|
|
241
|
-
<div className="text-sm font-medium text-[color:var(--ck-text-primary)]">Where to change settings</div>
|
|
242
|
-
<p className="mt-2 text-sm text-[color:var(--ck-text-secondary)]">
|
|
243
|
-
These are the common knobs for a swarm/orchestrator scaffold (read-only references):
|
|
244
|
-
</p>
|
|
245
|
-
<ul className="mt-2 list-disc space-y-1 pl-5 text-sm text-[color:var(--ck-text-secondary)]">
|
|
246
|
-
{state.settingsPaths.map((p) => (
|
|
247
|
-
<li key={p} className="font-mono text-xs">
|
|
248
|
-
{p}
|
|
249
|
-
</li>
|
|
250
|
-
))}
|
|
251
|
-
</ul>
|
|
252
|
-
</section>
|
|
253
|
-
</div>
|
|
254
|
-
);
|
|
255
|
-
}
|
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { useMemo, useState } from "react";
|
|
4
|
-
import { createPortal } from "react-dom";
|
|
5
|
-
import { fetchJson } from "@/lib/fetch-json";
|
|
6
|
-
|
|
7
|
-
function slugifyId(input: string) {
|
|
8
|
-
return String(input ?? "")
|
|
9
|
-
.toLowerCase()
|
|
10
|
-
.trim()
|
|
11
|
-
.replace(/[^a-z0-9]+/g, "-")
|
|
12
|
-
.replace(/^-+|-+$/g, "")
|
|
13
|
-
.replace(/--+/g, "-");
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function OrchestratorSetupModal({
|
|
17
|
-
open,
|
|
18
|
-
onClose,
|
|
19
|
-
teamId,
|
|
20
|
-
onInstalled,
|
|
21
|
-
}: {
|
|
22
|
-
open: boolean;
|
|
23
|
-
onClose: () => void;
|
|
24
|
-
teamId: string;
|
|
25
|
-
onInstalled: () => void;
|
|
26
|
-
}) {
|
|
27
|
-
const defaultAgentId = useMemo(() => `${teamId}-swarm-orchestrator`, [teamId]);
|
|
28
|
-
const [agentId, setAgentId] = useState(defaultAgentId);
|
|
29
|
-
const [repoDir, setRepoDir] = useState("");
|
|
30
|
-
const [worktreeRoot, setWorktreeRoot] = useState("/home/control/swarm-worktrees");
|
|
31
|
-
const [baseRef, setBaseRef] = useState("origin/main");
|
|
32
|
-
const [applyConfig, setApplyConfig] = useState(true);
|
|
33
|
-
const [makeExecutable, setMakeExecutable] = useState(true);
|
|
34
|
-
|
|
35
|
-
const [submitting, setSubmitting] = useState(false);
|
|
36
|
-
const [error, setError] = useState<string | null>(null);
|
|
37
|
-
const [result, setResult] = useState<{ orchestratorAgentId: string; workspace: string } | null>(null);
|
|
38
|
-
|
|
39
|
-
const normalized = useMemo(() => {
|
|
40
|
-
const effectiveAgentId = slugifyId(agentId);
|
|
41
|
-
return { effectiveAgentId };
|
|
42
|
-
}, [agentId]);
|
|
43
|
-
|
|
44
|
-
if (!open) return null;
|
|
45
|
-
|
|
46
|
-
return createPortal(
|
|
47
|
-
<div className="fixed inset-0 z-[210]">
|
|
48
|
-
<div
|
|
49
|
-
className="fixed inset-0 bg-black/60"
|
|
50
|
-
onClick={() => {
|
|
51
|
-
if (!submitting) onClose();
|
|
52
|
-
}}
|
|
53
|
-
/>
|
|
54
|
-
<div className="fixed inset-0 overflow-y-auto">
|
|
55
|
-
<div className="flex min-h-full items-center justify-center p-4">
|
|
56
|
-
<div className="w-full max-w-xl rounded-2xl border border-white/10 bg-[color:var(--ck-bg-glass-strong)] p-5 shadow-[var(--ck-shadow-2)]">
|
|
57
|
-
<div className="text-lg font-semibold text-[color:var(--ck-text-primary)]">Add Orchestrator</div>
|
|
58
|
-
<p className="mt-1 text-sm text-[color:var(--ck-text-secondary)]">
|
|
59
|
-
This will scaffold a new <span className="font-mono text-xs">swarm-orchestrator</span> agent workspace for this team and
|
|
60
|
-
prefill its config.
|
|
61
|
-
</p>
|
|
62
|
-
|
|
63
|
-
<label className="mt-4 block text-xs font-medium text-[color:var(--ck-text-secondary)]">Orchestrator agent id</label>
|
|
64
|
-
<input
|
|
65
|
-
value={agentId}
|
|
66
|
-
onChange={(e) => setAgentId(e.target.value)}
|
|
67
|
-
className="mt-1 w-full rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/25 px-3 py-2 text-sm text-[color:var(--ck-text-primary)]"
|
|
68
|
-
/>
|
|
69
|
-
<div className="mt-1 text-xs text-[color:var(--ck-text-tertiary)]">
|
|
70
|
-
Default: <span className="font-mono">{defaultAgentId}</span> (normalized: <span className="font-mono">{normalized.effectiveAgentId}</span>)
|
|
71
|
-
</div>
|
|
72
|
-
|
|
73
|
-
<label className="mt-4 block text-xs font-medium text-[color:var(--ck-text-secondary)]">Repo directory (SWARM_REPO_DIR)</label>
|
|
74
|
-
<input
|
|
75
|
-
value={repoDir}
|
|
76
|
-
onChange={(e) => setRepoDir(e.target.value)}
|
|
77
|
-
placeholder="/home/control/clawkitchen"
|
|
78
|
-
className="mt-1 w-full rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/25 px-3 py-2 text-sm text-[color:var(--ck-text-primary)]"
|
|
79
|
-
/>
|
|
80
|
-
|
|
81
|
-
<div className="mt-4 grid grid-cols-1 gap-3 md:grid-cols-2">
|
|
82
|
-
<div>
|
|
83
|
-
<label className="block text-xs font-medium text-[color:var(--ck-text-secondary)]">Worktree root (SWARM_WORKTREE_ROOT)</label>
|
|
84
|
-
<input
|
|
85
|
-
value={worktreeRoot}
|
|
86
|
-
onChange={(e) => setWorktreeRoot(e.target.value)}
|
|
87
|
-
className="mt-1 w-full rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/25 px-3 py-2 text-sm text-[color:var(--ck-text-primary)]"
|
|
88
|
-
/>
|
|
89
|
-
<div className="mt-1 text-xs text-[color:var(--ck-text-tertiary)]">Recommend a dedicated folder outside the repo.</div>
|
|
90
|
-
</div>
|
|
91
|
-
|
|
92
|
-
<div>
|
|
93
|
-
<label className="block text-xs font-medium text-[color:var(--ck-text-secondary)]">Base ref (SWARM_BASE_REF)</label>
|
|
94
|
-
<input
|
|
95
|
-
value={baseRef}
|
|
96
|
-
onChange={(e) => setBaseRef(e.target.value)}
|
|
97
|
-
className="mt-1 w-full rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/25 px-3 py-2 text-sm text-[color:var(--ck-text-primary)]"
|
|
98
|
-
/>
|
|
99
|
-
</div>
|
|
100
|
-
</div>
|
|
101
|
-
|
|
102
|
-
<label className="mt-5 flex items-start gap-2 rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/20 p-3 text-sm text-[color:var(--ck-text-secondary)]">
|
|
103
|
-
<input type="checkbox" checked={applyConfig} onChange={(e) => setApplyConfig(e.target.checked)} className="mt-1" />
|
|
104
|
-
<span>
|
|
105
|
-
Add this agent to OpenClaw config (recommended).<br />
|
|
106
|
-
<span className="text-xs text-[color:var(--ck-text-tertiary)]">
|
|
107
|
-
This will modify <span className="font-mono">~/.openclaw/openclaw.json</span> to add <span className="font-mono">{normalized.effectiveAgentId}</span>.
|
|
108
|
-
</span>
|
|
109
|
-
</span>
|
|
110
|
-
</label>
|
|
111
|
-
|
|
112
|
-
<label className="mt-3 flex items-start gap-2 rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/20 p-3 text-sm text-[color:var(--ck-text-secondary)]">
|
|
113
|
-
<input type="checkbox" checked={makeExecutable} onChange={(e) => setMakeExecutable(e.target.checked)} className="mt-1" />
|
|
114
|
-
<span>
|
|
115
|
-
Make scripts executable (developer convenience).<br />
|
|
116
|
-
<span className="text-xs text-[color:var(--ck-text-tertiary)]">
|
|
117
|
-
Runs <span className="font-mono">chmod +x .clawdbot/*.sh</span> in the orchestrator workspace.
|
|
118
|
-
</span>
|
|
119
|
-
</span>
|
|
120
|
-
</label>
|
|
121
|
-
|
|
122
|
-
{error ? (
|
|
123
|
-
<div className="mt-4 rounded-[var(--ck-radius-sm)] border border-red-400/30 bg-red-500/10 p-3 text-sm text-red-100">{error}</div>
|
|
124
|
-
) : null}
|
|
125
|
-
|
|
126
|
-
{result ? (
|
|
127
|
-
<div className="mt-4 rounded-[var(--ck-radius-sm)] border border-emerald-400/30 bg-emerald-500/10 p-3 text-sm text-emerald-100">
|
|
128
|
-
Installed <span className="font-mono">{result.orchestratorAgentId}</span> → <span className="font-mono">{result.workspace}</span>
|
|
129
|
-
</div>
|
|
130
|
-
) : null}
|
|
131
|
-
|
|
132
|
-
<div className="mt-6 flex items-center justify-end gap-2">
|
|
133
|
-
<button
|
|
134
|
-
type="button"
|
|
135
|
-
onClick={onClose}
|
|
136
|
-
disabled={submitting}
|
|
137
|
-
className="rounded-[var(--ck-radius-sm)] border border-white/10 bg-white/5 px-3 py-2 text-sm font-medium text-[color:var(--ck-text-primary)] hover:bg-white/10 disabled:opacity-50"
|
|
138
|
-
>
|
|
139
|
-
Cancel
|
|
140
|
-
</button>
|
|
141
|
-
<button
|
|
142
|
-
type="button"
|
|
143
|
-
disabled={submitting || !normalized.effectiveAgentId || !repoDir.trim()}
|
|
144
|
-
onClick={async () => {
|
|
145
|
-
setSubmitting(true);
|
|
146
|
-
setError(null);
|
|
147
|
-
setResult(null);
|
|
148
|
-
try {
|
|
149
|
-
const json = await fetchJson<
|
|
150
|
-
| { ok: true; orchestratorAgentId: string; workspace: string }
|
|
151
|
-
| { ok: false; error: string }
|
|
152
|
-
>("/api/teams/orchestrator/install", {
|
|
153
|
-
method: "POST",
|
|
154
|
-
headers: { "content-type": "application/json" },
|
|
155
|
-
body: JSON.stringify({
|
|
156
|
-
teamId,
|
|
157
|
-
orchestratorAgentId: normalized.effectiveAgentId,
|
|
158
|
-
repoDir: repoDir.trim(),
|
|
159
|
-
worktreeRoot: worktreeRoot.trim(),
|
|
160
|
-
baseRef: baseRef.trim(),
|
|
161
|
-
applyConfig,
|
|
162
|
-
makeExecutable,
|
|
163
|
-
}),
|
|
164
|
-
});
|
|
165
|
-
if (!json.ok) throw new Error(json.error);
|
|
166
|
-
setResult({ orchestratorAgentId: json.orchestratorAgentId, workspace: json.workspace });
|
|
167
|
-
onInstalled();
|
|
168
|
-
} catch (e: unknown) {
|
|
169
|
-
setError(e instanceof Error ? e.message : String(e));
|
|
170
|
-
} finally {
|
|
171
|
-
setSubmitting(false);
|
|
172
|
-
}
|
|
173
|
-
}}
|
|
174
|
-
className="rounded-[var(--ck-radius-sm)] bg-[var(--ck-accent-red)] px-3 py-2 text-sm font-medium text-white shadow-[var(--ck-shadow-1)] hover:bg-[var(--ck-accent-red-hover)] disabled:opacity-50"
|
|
175
|
-
>
|
|
176
|
-
{submitting ? "Installing…" : "Install"}
|
|
177
|
-
</button>
|
|
178
|
-
</div>
|
|
179
|
-
</div>
|
|
180
|
-
</div>
|
|
181
|
-
</div>
|
|
182
|
-
</div>
|
|
183
|
-
, document.body);
|
|
184
|
-
}
|