@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,349 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { useEffect, useMemo, useState } from "react";
|
|
4
|
-
import { errorMessage } from "@/lib/errors";
|
|
5
|
-
|
|
6
|
-
type MemoryItem = {
|
|
7
|
-
ts: string;
|
|
8
|
-
author: string;
|
|
9
|
-
type: string;
|
|
10
|
-
content: string;
|
|
11
|
-
source?: unknown;
|
|
12
|
-
_file?: string;
|
|
13
|
-
_line?: number;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
type PinnedItem = MemoryItem & {
|
|
17
|
-
pinnedAt: string;
|
|
18
|
-
pinnedBy: string;
|
|
19
|
-
_key: string;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
function memoryKey(it: { _file?: string; _line?: number }): string {
|
|
23
|
-
return `${it._file ?? ""}:${it._line ?? 0}`;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function TeamMemoryTab({ teamId }: { teamId: string }) {
|
|
27
|
-
const [loading, setLoading] = useState(false);
|
|
28
|
-
const [error, setError] = useState("");
|
|
29
|
-
const [files, setFiles] = useState<string[]>([]);
|
|
30
|
-
const [pinnedItems, setPinnedItems] = useState<PinnedItem[]>([]);
|
|
31
|
-
const [items, setItems] = useState<MemoryItem[]>([]);
|
|
32
|
-
|
|
33
|
-
const [newType, setNewType] = useState("learning");
|
|
34
|
-
const [newContent, setNewContent] = useState("");
|
|
35
|
-
const [newSource, setNewSource] = useState("");
|
|
36
|
-
const [saving, setSaving] = useState(false);
|
|
37
|
-
const [pinningKey, setPinningKey] = useState<string | null>(null);
|
|
38
|
-
|
|
39
|
-
async function refresh() {
|
|
40
|
-
setLoading(true);
|
|
41
|
-
setError("");
|
|
42
|
-
try {
|
|
43
|
-
const res = await fetch(`/api/teams/memory?teamId=${encodeURIComponent(teamId)}`, { cache: "no-store" });
|
|
44
|
-
const json = (await res.json()) as {
|
|
45
|
-
ok?: boolean;
|
|
46
|
-
error?: string;
|
|
47
|
-
files?: string[];
|
|
48
|
-
pinnedItems?: PinnedItem[];
|
|
49
|
-
items?: MemoryItem[];
|
|
50
|
-
};
|
|
51
|
-
if (!res.ok || !json.ok) throw new Error(json.error || "Failed to load memory");
|
|
52
|
-
setFiles(Array.isArray(json.files) ? json.files : []);
|
|
53
|
-
setPinnedItems(Array.isArray(json.pinnedItems) ? json.pinnedItems : []);
|
|
54
|
-
setItems(Array.isArray(json.items) ? json.items : []);
|
|
55
|
-
} catch (e: unknown) {
|
|
56
|
-
setError(errorMessage(e));
|
|
57
|
-
setFiles([]);
|
|
58
|
-
setPinnedItems([]);
|
|
59
|
-
setItems([]);
|
|
60
|
-
} finally {
|
|
61
|
-
setLoading(false);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
useEffect(() => {
|
|
66
|
-
void refresh();
|
|
67
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps -- refresh is defined inline; teamId is the only intended trigger.
|
|
68
|
-
}, [teamId]);
|
|
69
|
-
|
|
70
|
-
const examples = useMemo(
|
|
71
|
-
() => [
|
|
72
|
-
{ label: "decision", value: "decision" },
|
|
73
|
-
{ label: "learning", value: "learning" },
|
|
74
|
-
{ label: "bug", value: "bug" },
|
|
75
|
-
{ label: "customer", value: "customer" },
|
|
76
|
-
{ label: "release", value: "release" },
|
|
77
|
-
],
|
|
78
|
-
[]
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
const pinnedKeySet = useMemo(() => new Set(pinnedItems.map((x) => x._key)), [pinnedItems]);
|
|
82
|
-
|
|
83
|
-
async function pin(it: MemoryItem) {
|
|
84
|
-
const key = memoryKey(it);
|
|
85
|
-
if (!it._file || !it._line) return;
|
|
86
|
-
|
|
87
|
-
setPinningKey(key);
|
|
88
|
-
setError("");
|
|
89
|
-
try {
|
|
90
|
-
const payload = {
|
|
91
|
-
op: "pin",
|
|
92
|
-
ts: new Date().toISOString(),
|
|
93
|
-
actor: `${teamId}-lead`,
|
|
94
|
-
key: { file: "team.jsonl", line: it._line },
|
|
95
|
-
item: { ts: it.ts, author: it.author, type: it.type, content: it.content, source: it.source },
|
|
96
|
-
};
|
|
97
|
-
const res = await fetch(`/api/teams/memory?teamId=${encodeURIComponent(teamId)}`, {
|
|
98
|
-
method: "POST",
|
|
99
|
-
headers: { "content-type": "application/json" },
|
|
100
|
-
body: JSON.stringify(payload),
|
|
101
|
-
});
|
|
102
|
-
const json = (await res.json()) as { ok?: boolean; error?: string };
|
|
103
|
-
if (!res.ok || !json.ok) throw new Error(json.error || "Failed to pin");
|
|
104
|
-
await refresh();
|
|
105
|
-
} catch (e: unknown) {
|
|
106
|
-
setError(errorMessage(e));
|
|
107
|
-
} finally {
|
|
108
|
-
setPinningKey(null);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
async function unpin(it: { _file?: string; _line?: number }) {
|
|
113
|
-
const key = memoryKey(it);
|
|
114
|
-
if (!it._file || !it._line) return;
|
|
115
|
-
|
|
116
|
-
setPinningKey(key);
|
|
117
|
-
setError("");
|
|
118
|
-
try {
|
|
119
|
-
const payload = {
|
|
120
|
-
op: "unpin",
|
|
121
|
-
ts: new Date().toISOString(),
|
|
122
|
-
actor: `${teamId}-lead`,
|
|
123
|
-
key: { file: "team.jsonl", line: it._line },
|
|
124
|
-
};
|
|
125
|
-
const res = await fetch(`/api/teams/memory?teamId=${encodeURIComponent(teamId)}`, {
|
|
126
|
-
method: "POST",
|
|
127
|
-
headers: { "content-type": "application/json" },
|
|
128
|
-
body: JSON.stringify(payload),
|
|
129
|
-
});
|
|
130
|
-
const json = (await res.json()) as { ok?: boolean; error?: string };
|
|
131
|
-
if (!res.ok || !json.ok) throw new Error(json.error || "Failed to unpin");
|
|
132
|
-
await refresh();
|
|
133
|
-
} catch (e: unknown) {
|
|
134
|
-
setError(errorMessage(e));
|
|
135
|
-
} finally {
|
|
136
|
-
setPinningKey(null);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return (
|
|
141
|
-
<div className="space-y-4">
|
|
142
|
-
<div className="ck-glass p-4">
|
|
143
|
-
<div className="flex items-start justify-between gap-3">
|
|
144
|
-
<div>
|
|
145
|
-
<div className="text-sm font-medium text-[color:var(--ck-text-primary)]">Team memory (file-first)</div>
|
|
146
|
-
<div className="mt-1 text-xs text-[color:var(--ck-text-tertiary)]">
|
|
147
|
-
Stored in <span className="font-mono">shared-context/memory/*.jsonl</span>. Items must be attributable.
|
|
148
|
-
</div>
|
|
149
|
-
</div>
|
|
150
|
-
<button
|
|
151
|
-
type="button"
|
|
152
|
-
onClick={refresh}
|
|
153
|
-
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"
|
|
154
|
-
>
|
|
155
|
-
Refresh
|
|
156
|
-
</button>
|
|
157
|
-
</div>
|
|
158
|
-
|
|
159
|
-
{error ? (
|
|
160
|
-
<div className="mt-3 rounded border border-red-400/30 bg-red-500/10 p-2 text-sm text-red-100">{error}</div>
|
|
161
|
-
) : null}
|
|
162
|
-
|
|
163
|
-
<div className="mt-3 text-xs text-[color:var(--ck-text-secondary)]">Files: {files.length ? files.join(", ") : "(none)"}</div>
|
|
164
|
-
</div>
|
|
165
|
-
|
|
166
|
-
<div className="ck-glass p-4">
|
|
167
|
-
<div className="text-sm font-medium text-[color:var(--ck-text-primary)]">Add memory item</div>
|
|
168
|
-
<div className="mt-3 grid grid-cols-1 gap-3 md:grid-cols-2">
|
|
169
|
-
<label className="block">
|
|
170
|
-
<div className="text-[10px] uppercase tracking-wide text-[color:var(--ck-text-tertiary)]">type</div>
|
|
171
|
-
<select
|
|
172
|
-
value={newType}
|
|
173
|
-
onChange={(e) => setNewType(e.target.value)}
|
|
174
|
-
className="mt-1 w-full rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/25 px-2 py-2 text-sm text-[color:var(--ck-text-primary)]"
|
|
175
|
-
>
|
|
176
|
-
{examples.map((x) => (
|
|
177
|
-
<option key={x.value} value={x.value}>
|
|
178
|
-
{x.label}
|
|
179
|
-
</option>
|
|
180
|
-
))}
|
|
181
|
-
</select>
|
|
182
|
-
</label>
|
|
183
|
-
|
|
184
|
-
<label className="block">
|
|
185
|
-
<div className="text-[10px] uppercase tracking-wide text-[color:var(--ck-text-tertiary)]">source (ticket/pr/path)</div>
|
|
186
|
-
<input
|
|
187
|
-
value={newSource}
|
|
188
|
-
onChange={(e) => setNewSource(e.target.value)}
|
|
189
|
-
className="mt-1 w-full rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/25 px-2 py-2 text-sm text-[color:var(--ck-text-primary)]"
|
|
190
|
-
placeholder="e.g. ticket 0088, PR https://..., shared-context/DECISIONS.md"
|
|
191
|
-
/>
|
|
192
|
-
</label>
|
|
193
|
-
|
|
194
|
-
<label className="block md:col-span-2">
|
|
195
|
-
<div className="text-[10px] uppercase tracking-wide text-[color:var(--ck-text-tertiary)]">content</div>
|
|
196
|
-
<textarea
|
|
197
|
-
value={newContent}
|
|
198
|
-
onChange={(e) => setNewContent(e.target.value)}
|
|
199
|
-
className="mt-1 h-[110px] w-full resize-none rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/25 p-2 text-sm text-[color:var(--ck-text-primary)]"
|
|
200
|
-
placeholder="Write a small, specific memory item…"
|
|
201
|
-
/>
|
|
202
|
-
</label>
|
|
203
|
-
|
|
204
|
-
<div className="md:col-span-2">
|
|
205
|
-
<button
|
|
206
|
-
type="button"
|
|
207
|
-
disabled={saving || !newContent.trim()}
|
|
208
|
-
onClick={async () => {
|
|
209
|
-
setSaving(true);
|
|
210
|
-
setError("");
|
|
211
|
-
try {
|
|
212
|
-
const payload = {
|
|
213
|
-
op: "append",
|
|
214
|
-
ts: new Date().toISOString(),
|
|
215
|
-
author: `${teamId}-lead`,
|
|
216
|
-
type: newType,
|
|
217
|
-
content: newContent.trim(),
|
|
218
|
-
source: newSource.trim() ? { text: newSource.trim() } : undefined,
|
|
219
|
-
file: "team.jsonl",
|
|
220
|
-
};
|
|
221
|
-
const res = await fetch(`/api/teams/memory?teamId=${encodeURIComponent(teamId)}`, {
|
|
222
|
-
method: "POST",
|
|
223
|
-
headers: { "content-type": "application/json" },
|
|
224
|
-
body: JSON.stringify(payload),
|
|
225
|
-
});
|
|
226
|
-
const json = (await res.json()) as { ok?: boolean; error?: string };
|
|
227
|
-
if (!res.ok || !json.ok) throw new Error(json.error || "Failed to append memory");
|
|
228
|
-
setNewContent("");
|
|
229
|
-
setNewSource("");
|
|
230
|
-
await refresh();
|
|
231
|
-
} catch (e: unknown) {
|
|
232
|
-
setError(errorMessage(e));
|
|
233
|
-
} finally {
|
|
234
|
-
setSaving(false);
|
|
235
|
-
}
|
|
236
|
-
}}
|
|
237
|
-
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)] disabled:opacity-50"
|
|
238
|
-
>
|
|
239
|
-
{saving ? "Saving…" : "Append to team.jsonl"}
|
|
240
|
-
</button>
|
|
241
|
-
</div>
|
|
242
|
-
</div>
|
|
243
|
-
</div>
|
|
244
|
-
|
|
245
|
-
<div className="ck-glass p-4">
|
|
246
|
-
<div className="flex items-center justify-between gap-2">
|
|
247
|
-
<div className="text-sm font-medium text-[color:var(--ck-text-primary)]">Pinned memory</div>
|
|
248
|
-
<div className="text-xs text-[color:var(--ck-text-tertiary)]">{pinnedItems.length} pinned</div>
|
|
249
|
-
</div>
|
|
250
|
-
|
|
251
|
-
{loading ? <div className="mt-3 text-sm text-[color:var(--ck-text-secondary)]">Loading…</div> : null}
|
|
252
|
-
|
|
253
|
-
<div className="mt-3 space-y-3">
|
|
254
|
-
{pinnedItems.length ? (
|
|
255
|
-
pinnedItems.map((it) => (
|
|
256
|
-
<div key={it._key} className="rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/25 p-3">
|
|
257
|
-
<div className="flex flex-wrap items-center justify-between gap-2">
|
|
258
|
-
<div className="text-xs text-[color:var(--ck-text-tertiary)]">
|
|
259
|
-
<span className="font-mono">{it.ts}</span>
|
|
260
|
-
<span className="mx-2">•</span>
|
|
261
|
-
<span className="rounded bg-white/5 px-2 py-0.5 font-mono">{it.type}</span>
|
|
262
|
-
<span className="mx-2">•</span>
|
|
263
|
-
<span className="font-mono">{it.author}</span>
|
|
264
|
-
<span className="mx-2">•</span>
|
|
265
|
-
<span className="font-mono">pinned {it.pinnedAt}</span>
|
|
266
|
-
</div>
|
|
267
|
-
<button
|
|
268
|
-
type="button"
|
|
269
|
-
onClick={() => void unpin(it)}
|
|
270
|
-
disabled={pinningKey === it._key}
|
|
271
|
-
className="rounded-[var(--ck-radius-sm)] border border-white/10 bg-white/5 px-2 py-1 text-xs font-medium text-[color:var(--ck-text-primary)] hover:bg-white/10 disabled:opacity-50"
|
|
272
|
-
>
|
|
273
|
-
{pinningKey === it._key ? "Unpinning…" : "Unpin"}
|
|
274
|
-
</button>
|
|
275
|
-
</div>
|
|
276
|
-
|
|
277
|
-
<div className="mt-2 whitespace-pre-wrap text-sm text-[color:var(--ck-text-primary)]">{it.content}</div>
|
|
278
|
-
|
|
279
|
-
{it.source ? (
|
|
280
|
-
<pre className="mt-2 overflow-auto rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/30 p-2 text-[10px] text-[color:var(--ck-text-secondary)]">
|
|
281
|
-
{JSON.stringify(it.source, null, 2)}
|
|
282
|
-
</pre>
|
|
283
|
-
) : null}
|
|
284
|
-
</div>
|
|
285
|
-
))
|
|
286
|
-
) : (
|
|
287
|
-
<div className="text-sm text-[color:var(--ck-text-secondary)]">No pinned items yet.</div>
|
|
288
|
-
)}
|
|
289
|
-
</div>
|
|
290
|
-
</div>
|
|
291
|
-
|
|
292
|
-
<div className="ck-glass p-4">
|
|
293
|
-
<div className="flex items-center justify-between gap-2">
|
|
294
|
-
<div className="text-sm font-medium text-[color:var(--ck-text-primary)]">Recent memory</div>
|
|
295
|
-
<div className="text-xs text-[color:var(--ck-text-tertiary)]">Showing {items.length} (max 200)</div>
|
|
296
|
-
</div>
|
|
297
|
-
|
|
298
|
-
{loading ? <div className="mt-3 text-sm text-[color:var(--ck-text-secondary)]">Loading…</div> : null}
|
|
299
|
-
|
|
300
|
-
<div className="mt-3 space-y-3">
|
|
301
|
-
{items.length ? (
|
|
302
|
-
items.map((it) => {
|
|
303
|
-
const k = memoryKey(it);
|
|
304
|
-
const isPinned = pinnedKeySet.has(k);
|
|
305
|
-
return (
|
|
306
|
-
<div key={`${it._file ?? "?"}:${it._line ?? 0}`} className="rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/25 p-3">
|
|
307
|
-
<div className="flex flex-wrap items-center justify-between gap-2">
|
|
308
|
-
<div className="text-xs text-[color:var(--ck-text-tertiary)]">
|
|
309
|
-
<span className="font-mono">{it.ts}</span>
|
|
310
|
-
<span className="mx-2">•</span>
|
|
311
|
-
<span className="rounded bg-white/5 px-2 py-0.5 font-mono">{it.type}</span>
|
|
312
|
-
<span className="mx-2">•</span>
|
|
313
|
-
<span className="font-mono">{it.author}</span>
|
|
314
|
-
</div>
|
|
315
|
-
<div className="flex items-center gap-2">
|
|
316
|
-
{it._file ? (
|
|
317
|
-
<span className="text-[10px] text-[color:var(--ck-text-tertiary)] font-mono">
|
|
318
|
-
{it._file}:{it._line}
|
|
319
|
-
</span>
|
|
320
|
-
) : null}
|
|
321
|
-
<button
|
|
322
|
-
type="button"
|
|
323
|
-
onClick={() => void pin(it)}
|
|
324
|
-
disabled={isPinned || pinningKey === k || !it._file || !it._line}
|
|
325
|
-
className="rounded-[var(--ck-radius-sm)] border border-white/10 bg-white/5 px-2 py-1 text-xs font-medium text-[color:var(--ck-text-primary)] hover:bg-white/10 disabled:opacity-50"
|
|
326
|
-
>
|
|
327
|
-
{isPinned ? "Pinned" : pinningKey === k ? "Pinning…" : "Pin"}
|
|
328
|
-
</button>
|
|
329
|
-
</div>
|
|
330
|
-
</div>
|
|
331
|
-
|
|
332
|
-
<div className="mt-2 whitespace-pre-wrap text-sm text-[color:var(--ck-text-primary)]">{it.content}</div>
|
|
333
|
-
|
|
334
|
-
{it.source ? (
|
|
335
|
-
<pre className="mt-2 overflow-auto rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/30 p-2 text-[10px] text-[color:var(--ck-text-secondary)]">
|
|
336
|
-
{JSON.stringify(it.source, null, 2)}
|
|
337
|
-
</pre>
|
|
338
|
-
) : null}
|
|
339
|
-
</div>
|
|
340
|
-
);
|
|
341
|
-
})
|
|
342
|
-
) : (
|
|
343
|
-
<div className="text-sm text-[color:var(--ck-text-secondary)]">No memory items yet.</div>
|
|
344
|
-
)}
|
|
345
|
-
</div>
|
|
346
|
-
</div>
|
|
347
|
-
</div>
|
|
348
|
-
);
|
|
349
|
-
}
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import type { RecipeListItem } from "./types";
|
|
4
|
-
|
|
5
|
-
type TeamRecipeTabProps = {
|
|
6
|
-
loading?: boolean;
|
|
7
|
-
fromId: string;
|
|
8
|
-
setFromId: (v: string) => void;
|
|
9
|
-
toId: string;
|
|
10
|
-
setToId: (v: string) => void;
|
|
11
|
-
toName: string;
|
|
12
|
-
setToName: (v: string) => void;
|
|
13
|
-
canEditTargetId: boolean;
|
|
14
|
-
teamRecipes: RecipeListItem[];
|
|
15
|
-
lockedFromId: string | null;
|
|
16
|
-
lockedFromName: string | null;
|
|
17
|
-
provenanceMissing: boolean;
|
|
18
|
-
saving: boolean;
|
|
19
|
-
teamIdValid: boolean;
|
|
20
|
-
targetIdValid: boolean;
|
|
21
|
-
targetIsBuiltin: boolean;
|
|
22
|
-
loadedRecipeHash: string | null;
|
|
23
|
-
teamMetaRecipeHash: string | null;
|
|
24
|
-
publishing: boolean;
|
|
25
|
-
content: string;
|
|
26
|
-
setContent: (v: string) => void;
|
|
27
|
-
setLoadedRecipeHash: (v: string | null) => void;
|
|
28
|
-
recipeLoadError: string;
|
|
29
|
-
onSaveCustom: (overwrite: boolean) => void;
|
|
30
|
-
onPublishOpen: () => void;
|
|
31
|
-
onDeleteOpen: () => void;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export function TeamRecipeTab(props: TeamRecipeTabProps) {
|
|
35
|
-
const p = props;
|
|
36
|
-
return (
|
|
37
|
-
<>
|
|
38
|
-
<div className="mt-6 grid grid-cols-1 gap-4 lg:grid-cols-2">
|
|
39
|
-
<div className="ck-glass-strong p-4">
|
|
40
|
-
<div className="flex items-center justify-between gap-3">
|
|
41
|
-
<div className="text-sm font-medium text-[color:var(--ck-text-primary)]">Custom recipe target</div>
|
|
42
|
-
{p.loading ? (
|
|
43
|
-
<div className="text-xs text-[color:var(--ck-text-tertiary)]">Loading team…</div>
|
|
44
|
-
) : null}
|
|
45
|
-
</div>
|
|
46
|
-
<label className="mt-3 block text-xs font-medium text-[color:var(--ck-text-secondary)]">Team id</label>
|
|
47
|
-
<input
|
|
48
|
-
value={p.toId}
|
|
49
|
-
onChange={(e) => p.setToId(e.target.value)}
|
|
50
|
-
disabled={!p.canEditTargetId}
|
|
51
|
-
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)] disabled:opacity-70"
|
|
52
|
-
/>
|
|
53
|
-
<div className="mt-1 text-xs text-[color:var(--ck-text-tertiary)]">
|
|
54
|
-
This is the custom recipe id that will be created when you save.
|
|
55
|
-
</div>
|
|
56
|
-
<label className="mt-3 block text-xs font-medium text-[color:var(--ck-text-secondary)]">Team name</label>
|
|
57
|
-
<input
|
|
58
|
-
value={p.toName}
|
|
59
|
-
onChange={(e) => p.setToName(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
|
-
<div className="mt-4 grid grid-cols-1 gap-2">
|
|
63
|
-
<button
|
|
64
|
-
type="button"
|
|
65
|
-
disabled={p.saving || !p.teamIdValid || !p.targetIdValid || p.targetIsBuiltin}
|
|
66
|
-
onClick={() => p.onSaveCustom(true)}
|
|
67
|
-
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)] disabled:opacity-50"
|
|
68
|
-
>
|
|
69
|
-
{p.saving ? "Saving" : "Save"}
|
|
70
|
-
</button>
|
|
71
|
-
<button
|
|
72
|
-
type="button"
|
|
73
|
-
disabled={
|
|
74
|
-
p.saving ||
|
|
75
|
-
!p.teamIdValid ||
|
|
76
|
-
!p.targetIdValid ||
|
|
77
|
-
p.targetIsBuiltin ||
|
|
78
|
-
!p.loadedRecipeHash ||
|
|
79
|
-
!p.teamMetaRecipeHash ||
|
|
80
|
-
p.loadedRecipeHash === p.teamMetaRecipeHash
|
|
81
|
-
}
|
|
82
|
-
onClick={p.onPublishOpen}
|
|
83
|
-
className="rounded-[var(--ck-radius-sm)] bg-emerald-600 px-3 py-2 text-sm font-medium text-white shadow-[var(--ck-shadow-1)] disabled:opacity-50"
|
|
84
|
-
>
|
|
85
|
-
{p.publishing ? "Publishing" : "Publish changes"}
|
|
86
|
-
</button>
|
|
87
|
-
<button
|
|
88
|
-
type="button"
|
|
89
|
-
disabled={p.saving}
|
|
90
|
-
onClick={p.onDeleteOpen}
|
|
91
|
-
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)] disabled:opacity-50"
|
|
92
|
-
>
|
|
93
|
-
Delete Team
|
|
94
|
-
</button>
|
|
95
|
-
</div>
|
|
96
|
-
</div>
|
|
97
|
-
<div className="ck-glass-strong p-4">
|
|
98
|
-
<div className="text-sm font-medium text-[color:var(--ck-text-primary)]">Notes</div>
|
|
99
|
-
<div className="mt-3 rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/20 p-3">
|
|
100
|
-
<div className="text-xs font-medium text-[color:var(--ck-text-secondary)]">Parent recipe (locked)</div>
|
|
101
|
-
<select
|
|
102
|
-
disabled
|
|
103
|
-
className="mt-2 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)] disabled:opacity-70"
|
|
104
|
-
value={p.fromId}
|
|
105
|
-
onChange={(e) => p.setFromId(e.target.value)}
|
|
106
|
-
>
|
|
107
|
-
{p.teamRecipes.map((r) => (
|
|
108
|
-
<option key={`${r.source}:${r.id}`} value={r.id}>
|
|
109
|
-
{r.id} ({r.source})
|
|
110
|
-
</option>
|
|
111
|
-
))}
|
|
112
|
-
</select>
|
|
113
|
-
{p.lockedFromId && (
|
|
114
|
-
<div className="mt-2 text-xs text-[color:var(--ck-text-tertiary)]">
|
|
115
|
-
<code>{p.lockedFromId}</code>
|
|
116
|
-
{p.lockedFromName ? ` (${p.lockedFromName})` : ""}
|
|
117
|
-
</div>
|
|
118
|
-
)}
|
|
119
|
-
{!p.lockedFromId && p.provenanceMissing && (
|
|
120
|
-
<div className="mt-2 text-xs text-[color:var(--ck-text-tertiary)]">
|
|
121
|
-
Provenance not found for this team.
|
|
122
|
-
</div>
|
|
123
|
-
)}
|
|
124
|
-
</div>
|
|
125
|
-
<ul className="mt-4 list-disc space-y-1 pl-5 text-sm text-[color:var(--ck-text-secondary)]">
|
|
126
|
-
<li>Save writes the custom recipe file identified by Team id.</li>
|
|
127
|
-
<li>Publish changes re-scaffolds this team from your custom recipe.</li>
|
|
128
|
-
<li>Delete Team runs openclaw recipes remove-team.</li>
|
|
129
|
-
</ul>
|
|
130
|
-
</div>
|
|
131
|
-
</div>
|
|
132
|
-
<div className="mt-6 ck-glass-strong p-4">
|
|
133
|
-
<div className="text-sm font-medium text-[color:var(--ck-text-primary)]">Recipe markdown</div>
|
|
134
|
-
{p.recipeLoadError ? (
|
|
135
|
-
<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">
|
|
136
|
-
{p.recipeLoadError}
|
|
137
|
-
</div>
|
|
138
|
-
) : null}
|
|
139
|
-
<textarea
|
|
140
|
-
value={p.content}
|
|
141
|
-
onChange={(e) => {
|
|
142
|
-
p.setContent(e.target.value);
|
|
143
|
-
p.setLoadedRecipeHash(null);
|
|
144
|
-
}}
|
|
145
|
-
className="mt-2 h-[55vh] w-full resize-none rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/25 p-3 font-mono text-xs text-[color:var(--ck-text-primary)]"
|
|
146
|
-
spellCheck={false}
|
|
147
|
-
/>
|
|
148
|
-
</div>
|
|
149
|
-
</>
|
|
150
|
-
);
|
|
151
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
type TeamSkillsTabProps = {
|
|
4
|
-
teamId: string;
|
|
5
|
-
skillsList: string[];
|
|
6
|
-
availableSkills: string[];
|
|
7
|
-
skillsLoading: boolean;
|
|
8
|
-
selectedSkill: string;
|
|
9
|
-
setSelectedSkill: (v: string) => void;
|
|
10
|
-
installingSkill: boolean;
|
|
11
|
-
teamSkillMsg: string;
|
|
12
|
-
teamSkillError: string;
|
|
13
|
-
onInstallSkill: () => Promise<void>;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export function TeamSkillsTab(props: TeamSkillsTabProps) {
|
|
17
|
-
const p = props;
|
|
18
|
-
return (
|
|
19
|
-
<div className="mt-6 ck-glass-strong p-4">
|
|
20
|
-
<div className="text-sm font-medium text-[color:var(--ck-text-primary)]">Skills</div>
|
|
21
|
-
<p className="mt-2 text-sm text-[color:var(--ck-text-secondary)]">
|
|
22
|
-
Skills installed in this team workspace. For agent-specific skills, open the agent from the Agents tab.
|
|
23
|
-
</p>
|
|
24
|
-
<div className="mt-4">
|
|
25
|
-
<div className="text-xs font-medium text-[color:var(--ck-text-secondary)]">Installed</div>
|
|
26
|
-
<ul className="mt-2 list-disc space-y-1 pl-5 text-sm text-[color:var(--ck-text-secondary)]">
|
|
27
|
-
{p.skillsList.length ? p.skillsList.map((s) => <li key={s}>{s}</li>) : <li>None installed.</li>}
|
|
28
|
-
</ul>
|
|
29
|
-
</div>
|
|
30
|
-
<div className="mt-5 rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/15 p-3">
|
|
31
|
-
<div className="text-xs font-medium text-[color:var(--ck-text-secondary)]">Add a skill</div>
|
|
32
|
-
<div className="mt-2 flex flex-col gap-2 sm:flex-row sm:items-center">
|
|
33
|
-
<select
|
|
34
|
-
value={p.selectedSkill}
|
|
35
|
-
onChange={(e) => p.setSelectedSkill(e.target.value)}
|
|
36
|
-
disabled={p.installingSkill || p.skillsLoading || !p.availableSkills.length}
|
|
37
|
-
className="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)]"
|
|
38
|
-
>
|
|
39
|
-
{p.availableSkills.length
|
|
40
|
-
? p.availableSkills.map((s) => <option key={s} value={s}>{s}</option>)
|
|
41
|
-
: <option value="">No skills found</option>}
|
|
42
|
-
</select>
|
|
43
|
-
<button
|
|
44
|
-
type="button"
|
|
45
|
-
disabled={p.installingSkill || p.skillsLoading || !p.selectedSkill}
|
|
46
|
-
onClick={p.onInstallSkill}
|
|
47
|
-
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)] disabled:opacity-50"
|
|
48
|
-
>
|
|
49
|
-
{p.installingSkill ? "Adding" : "Add"}
|
|
50
|
-
</button>
|
|
51
|
-
</div>
|
|
52
|
-
{p.teamSkillError && (
|
|
53
|
-
<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">
|
|
54
|
-
{p.teamSkillError}
|
|
55
|
-
</div>
|
|
56
|
-
)}
|
|
57
|
-
{p.teamSkillMsg && (
|
|
58
|
-
<div className="mt-3 rounded-[var(--ck-radius-sm)] border border-emerald-400/30 bg-emerald-500/10 p-3 text-sm text-emerald-100">
|
|
59
|
-
{p.teamSkillMsg}
|
|
60
|
-
</div>
|
|
61
|
-
)}
|
|
62
|
-
<div className="mt-2 text-xs text-[color:var(--ck-text-tertiary)]">
|
|
63
|
-
Uses openclaw recipes install-skill with team-id {p.teamId}.
|
|
64
|
-
</div>
|
|
65
|
-
</div>
|
|
66
|
-
</div>
|
|
67
|
-
);
|
|
68
|
-
}
|