@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,119 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
|
|
4
|
-
import { NextResponse } from "next/server";
|
|
5
|
-
|
|
6
|
-
import { slugifyFilePart, ensureWorkflowInstructions } from "@/lib/goal-promote";
|
|
7
|
-
import { goalErrorResponse, readGoal, writeGoal } from "@/lib/goals";
|
|
8
|
-
import { getTeamWorkspaceDir, readOpenClawConfig } from "@/lib/paths";
|
|
9
|
-
import { errorMessage } from "@/lib/errors";
|
|
10
|
-
import { runOpenClaw } from "@/lib/openclaw";
|
|
11
|
-
|
|
12
|
-
export async function POST(_: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
13
|
-
try {
|
|
14
|
-
const { id } = await params;
|
|
15
|
-
const goalId = decodeURIComponent(id);
|
|
16
|
-
|
|
17
|
-
const existing = await readGoal(goalId);
|
|
18
|
-
if (!existing) return NextResponse.json({ error: "Goal not found" }, { status: 404 });
|
|
19
|
-
|
|
20
|
-
// 1) Create inbox item for development-team lead to scope
|
|
21
|
-
const teamId = "development-team";
|
|
22
|
-
const teamWs = await getTeamWorkspaceDir(teamId);
|
|
23
|
-
const inboxDir = path.join(teamWs, "inbox");
|
|
24
|
-
await fs.mkdir(inboxDir, { recursive: true });
|
|
25
|
-
|
|
26
|
-
const received = new Date().toISOString();
|
|
27
|
-
const stamp = received.replace(/[-:]/g, "").split(".")[0] ?? received;
|
|
28
|
-
const titlePart = slugifyFilePart(existing.frontmatter.title || goalId);
|
|
29
|
-
const filename = `${received.slice(0, 10)}-${received.slice(11, 16).replace(":", "")}-goal-${titlePart || goalId}.md`;
|
|
30
|
-
|
|
31
|
-
const inboxBody = [
|
|
32
|
-
"# Inbox — development-team",
|
|
33
|
-
"",
|
|
34
|
-
`Received: ${received}`,
|
|
35
|
-
"",
|
|
36
|
-
"## Request",
|
|
37
|
-
`Goal: ${existing.frontmatter.title} (${goalId})`,
|
|
38
|
-
"",
|
|
39
|
-
"## Proposed work",
|
|
40
|
-
"- Ticket: (lead to create during scoping)",
|
|
41
|
-
"- Owner: lead",
|
|
42
|
-
"",
|
|
43
|
-
"## Links",
|
|
44
|
-
`- Goal UI: /goals/${encodeURIComponent(goalId)}`,
|
|
45
|
-
`- Goal file: ~/.openclaw/workspace/notes/goals/${goalId}.md`,
|
|
46
|
-
"",
|
|
47
|
-
"## Goal body (snapshot)",
|
|
48
|
-
existing.body?.trim() ? existing.body.trim() : "(empty)",
|
|
49
|
-
"",
|
|
50
|
-
].join("\n");
|
|
51
|
-
|
|
52
|
-
const inboxPath = path.join(inboxDir, filename);
|
|
53
|
-
await fs.writeFile(inboxPath, inboxBody, { encoding: "utf8", flag: "wx" }).catch(async (e: unknown) => {
|
|
54
|
-
const code = (e && typeof e === "object" && "code" in e) ? String((e as { code?: unknown }).code) : "";
|
|
55
|
-
if (code === "EEXIST") {
|
|
56
|
-
const alt = path.join(inboxDir, filename.replace(/\.md$/, `-${stamp}.md`));
|
|
57
|
-
await fs.writeFile(alt, inboxBody, { encoding: "utf8", flag: "wx" });
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
throw e;
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
// 2) Mark goal active + ensure workflow instructions exist
|
|
64
|
-
const updatedBody = ensureWorkflowInstructions(existing.body ?? "");
|
|
65
|
-
const updated = await writeGoal({
|
|
66
|
-
id: goalId,
|
|
67
|
-
title: existing.frontmatter.title,
|
|
68
|
-
status: "active",
|
|
69
|
-
tags: existing.frontmatter.tags,
|
|
70
|
-
teams: existing.frontmatter.teams,
|
|
71
|
-
body: updatedBody,
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
const cfg = await readOpenClawConfig();
|
|
75
|
-
const enabled = cfg.tools?.agentToAgent?.enabled === true;
|
|
76
|
-
const allow = cfg.tools?.agentToAgent?.allow ?? [];
|
|
77
|
-
const targetAgentId = "development-team-lead";
|
|
78
|
-
const permitted = enabled && (allow.includes("*") || allow.includes(targetAgentId));
|
|
79
|
-
|
|
80
|
-
let pingAttempted = false;
|
|
81
|
-
let pingOk = false;
|
|
82
|
-
let pingReason: string | null = null;
|
|
83
|
-
|
|
84
|
-
if (!permitted) {
|
|
85
|
-
pingReason = enabled
|
|
86
|
-
? `agentToAgent.allow does not include "*" or "${targetAgentId}"`
|
|
87
|
-
: "tools.agentToAgent.enabled is false";
|
|
88
|
-
} else {
|
|
89
|
-
pingAttempted = true;
|
|
90
|
-
try {
|
|
91
|
-
const res = await runOpenClaw([
|
|
92
|
-
"agent",
|
|
93
|
-
"--agent",
|
|
94
|
-
targetAgentId,
|
|
95
|
-
"--message",
|
|
96
|
-
`New goal promoted to development-team inbox: ${updated.frontmatter.title} (${goalId}). Inbox file: ${inboxPath}`,
|
|
97
|
-
"--timeout",
|
|
98
|
-
"60",
|
|
99
|
-
"--json",
|
|
100
|
-
]);
|
|
101
|
-
if (!res.ok) throw new Error(res.stderr || `openclaw exit ${res.exitCode}`);
|
|
102
|
-
pingOk = true;
|
|
103
|
-
} catch (e: unknown) {
|
|
104
|
-
pingReason = errorMessage(e);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return NextResponse.json({
|
|
109
|
-
ok: true,
|
|
110
|
-
goal: updated.frontmatter,
|
|
111
|
-
inboxPath,
|
|
112
|
-
pingAttempted,
|
|
113
|
-
pingOk,
|
|
114
|
-
pingReason,
|
|
115
|
-
});
|
|
116
|
-
} catch (e: unknown) {
|
|
117
|
-
return goalErrorResponse(e);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
import { deleteGoal, goalErrorResponse, readGoal, writeGoal } from "@/lib/goals";
|
|
3
|
-
|
|
4
|
-
export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
5
|
-
const { id } = await params;
|
|
6
|
-
try {
|
|
7
|
-
const goal = await readGoal(id);
|
|
8
|
-
if (!goal) return NextResponse.json({ error: "Not found" }, { status: 404 });
|
|
9
|
-
return NextResponse.json({ goal: goal.frontmatter, body: goal.body, raw: goal.raw });
|
|
10
|
-
} catch (e: unknown) {
|
|
11
|
-
return goalErrorResponse(e);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export async function PUT(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
16
|
-
const { id } = await params;
|
|
17
|
-
type GoalPutBody = {
|
|
18
|
-
title: string;
|
|
19
|
-
status?: "planned" | "active" | "done";
|
|
20
|
-
tags?: string[];
|
|
21
|
-
teams?: string[];
|
|
22
|
-
body?: string;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
try {
|
|
26
|
-
const data = (await req.json()) as GoalPutBody;
|
|
27
|
-
const title = String(data?.title ?? "").trim();
|
|
28
|
-
if (!title) return NextResponse.json({ error: "title is required" }, { status: 400 });
|
|
29
|
-
|
|
30
|
-
const result = await writeGoal({
|
|
31
|
-
id,
|
|
32
|
-
title,
|
|
33
|
-
status: data?.status,
|
|
34
|
-
tags: Array.isArray(data?.tags) ? data.tags : [],
|
|
35
|
-
teams: Array.isArray(data?.teams) ? data.teams : [],
|
|
36
|
-
body: String(data?.body ?? ""),
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
return NextResponse.json({ goal: result.frontmatter });
|
|
40
|
-
} catch (e: unknown) {
|
|
41
|
-
return goalErrorResponse(e);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export async function DELETE(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
46
|
-
const { id } = await params;
|
|
47
|
-
try {
|
|
48
|
-
const result = await deleteGoal(id);
|
|
49
|
-
if (!result.ok) return NextResponse.json({ error: "Not found" }, { status: 404 });
|
|
50
|
-
return NextResponse.json({ ok: true });
|
|
51
|
-
} catch (e: unknown) {
|
|
52
|
-
return goalErrorResponse(e);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
import { goalErrorResponse, listGoals, writeGoal } from "@/lib/goals";
|
|
3
|
-
|
|
4
|
-
export async function GET() {
|
|
5
|
-
try {
|
|
6
|
-
const goals = await listGoals();
|
|
7
|
-
return NextResponse.json({ goals });
|
|
8
|
-
} catch (e: unknown) {
|
|
9
|
-
return goalErrorResponse(e);
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
type GoalWriteBody = {
|
|
14
|
-
id: string;
|
|
15
|
-
title: string;
|
|
16
|
-
status?: "planned" | "active" | "done";
|
|
17
|
-
tags?: string[];
|
|
18
|
-
teams?: string[];
|
|
19
|
-
body?: string;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export async function POST(req: Request) {
|
|
23
|
-
try {
|
|
24
|
-
const body = (await req.json()) as GoalWriteBody;
|
|
25
|
-
const id = String(body?.id ?? "").trim();
|
|
26
|
-
const title = String(body?.title ?? "").trim();
|
|
27
|
-
if (!id || !title) {
|
|
28
|
-
return NextResponse.json({ error: "id and title are required" }, { status: 400 });
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const result = await writeGoal({
|
|
32
|
-
id,
|
|
33
|
-
title,
|
|
34
|
-
status: body?.status,
|
|
35
|
-
tags: Array.isArray(body?.tags) ? body.tags : [],
|
|
36
|
-
teams: Array.isArray(body?.teams) ? body.teams : [],
|
|
37
|
-
body: String(body?.body ?? ""),
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
return NextResponse.json({ goal: result.frontmatter });
|
|
41
|
-
} catch (e: unknown) {
|
|
42
|
-
return goalErrorResponse(e);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
import fs from "node:fs/promises";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { runOpenClaw } from "@/lib/openclaw";
|
|
5
|
-
import { errorMessage } from "@/lib/errors";
|
|
6
|
-
import { readOpenClawConfig } from "@/lib/paths";
|
|
7
|
-
|
|
8
|
-
type Kind = "team" | "agent";
|
|
9
|
-
|
|
10
|
-
type Snapshot = {
|
|
11
|
-
atMs: number;
|
|
12
|
-
recipeIds: Set<string>;
|
|
13
|
-
agentIds: Set<string>;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const SNAPSHOT_TTL_MS = 10_000;
|
|
17
|
-
let snapshot: Snapshot | null = null;
|
|
18
|
-
let snapshotPromise: Promise<Snapshot> | null = null;
|
|
19
|
-
|
|
20
|
-
function normalizeId(v: unknown) {
|
|
21
|
-
return String(v ?? "").trim();
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function parseIdsFromJson(stdout: string): Set<string> {
|
|
25
|
-
const ids = new Set<string>();
|
|
26
|
-
try {
|
|
27
|
-
const items = JSON.parse(stdout) as Array<{ id?: unknown }>;
|
|
28
|
-
for (const item of items) {
|
|
29
|
-
const id = normalizeId(item.id);
|
|
30
|
-
if (id) ids.add(id);
|
|
31
|
-
}
|
|
32
|
-
} catch {
|
|
33
|
-
// ignore
|
|
34
|
-
}
|
|
35
|
-
return ids;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async function getSnapshot(): Promise<Snapshot> {
|
|
39
|
-
const now = Date.now();
|
|
40
|
-
if (snapshot && now - snapshot.atMs < SNAPSHOT_TTL_MS) return snapshot;
|
|
41
|
-
if (snapshotPromise) return snapshotPromise;
|
|
42
|
-
|
|
43
|
-
snapshotPromise = (async () => {
|
|
44
|
-
const [recipesRes, agentsRes] = await Promise.all([
|
|
45
|
-
runOpenClaw(["recipes", "list"]),
|
|
46
|
-
runOpenClaw(["agents", "list", "--json"]),
|
|
47
|
-
]);
|
|
48
|
-
|
|
49
|
-
const recipeIds = recipesRes.ok ? parseIdsFromJson(recipesRes.stdout) : new Set<string>();
|
|
50
|
-
const agentIds = agentsRes.ok ? parseIdsFromJson(agentsRes.stdout) : new Set<string>();
|
|
51
|
-
|
|
52
|
-
const s: Snapshot = { atMs: now, recipeIds, agentIds };
|
|
53
|
-
snapshot = s;
|
|
54
|
-
snapshotPromise = null;
|
|
55
|
-
return s;
|
|
56
|
-
})();
|
|
57
|
-
|
|
58
|
-
return snapshotPromise;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export async function GET(req: Request) {
|
|
62
|
-
try {
|
|
63
|
-
const url = new URL(req.url);
|
|
64
|
-
const kind = normalizeId(url.searchParams.get("kind")) as Kind;
|
|
65
|
-
const id = normalizeId(url.searchParams.get("id"));
|
|
66
|
-
|
|
67
|
-
if (kind !== "team" && kind !== "agent") {
|
|
68
|
-
return NextResponse.json({ ok: false, error: "kind must be team|agent" }, { status: 400 });
|
|
69
|
-
}
|
|
70
|
-
if (!id) {
|
|
71
|
-
return NextResponse.json({ ok: true, available: false, reason: "empty" });
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const snap = await getSnapshot();
|
|
75
|
-
|
|
76
|
-
// Disallow collisions with any recipe id.
|
|
77
|
-
if (snap.recipeIds.has(id)) {
|
|
78
|
-
return NextResponse.json({ ok: true, available: false, reason: "recipe-id-collision" });
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (kind === "agent") {
|
|
82
|
-
if (snap.agentIds.has(id)) return NextResponse.json({ ok: true, available: false, reason: "agent-exists" });
|
|
83
|
-
return NextResponse.json({ ok: true, available: true });
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Team id: check team workspace dir and any team agents prefix.
|
|
87
|
-
try {
|
|
88
|
-
const cfg = await readOpenClawConfig();
|
|
89
|
-
const baseWorkspace = normalizeId(cfg.agents?.defaults?.workspace);
|
|
90
|
-
if (baseWorkspace) {
|
|
91
|
-
const teamDir = path.resolve(baseWorkspace, "..", `workspace-${id}`);
|
|
92
|
-
const hasDir = await fs
|
|
93
|
-
.stat(teamDir)
|
|
94
|
-
.then(() => true)
|
|
95
|
-
.catch(() => false);
|
|
96
|
-
if (hasDir) return NextResponse.json({ ok: true, available: false, reason: "team-workspace-exists" });
|
|
97
|
-
}
|
|
98
|
-
} catch {
|
|
99
|
-
// ignore
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const snap2 = await getSnapshot();
|
|
103
|
-
const hasAgents = Array.from(snap2.agentIds).some((a) => a.startsWith(`${id}-`));
|
|
104
|
-
if (hasAgents) return NextResponse.json({ ok: true, available: false, reason: "team-agents-exist" });
|
|
105
|
-
|
|
106
|
-
return NextResponse.json({ ok: true, available: true });
|
|
107
|
-
} catch (e: unknown) {
|
|
108
|
-
return NextResponse.json(
|
|
109
|
-
{ ok: false, error: errorMessage(e) },
|
|
110
|
-
{ status: 500 },
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { NextRequest, NextResponse } from "next/server";
|
|
2
|
-
import { getBySlug, loadRegistry } from "@/lib/marketplace";
|
|
3
|
-
|
|
4
|
-
export async function GET(_req: NextRequest, { params }: { params: Promise<{ slug: string }> }) {
|
|
5
|
-
try {
|
|
6
|
-
const { slug } = await params;
|
|
7
|
-
const registry = await loadRegistry();
|
|
8
|
-
const recipe = getBySlug(registry.recipes, slug);
|
|
9
|
-
if (!recipe) return NextResponse.json({ ok: false, error: "Not found" }, { status: 404 });
|
|
10
|
-
|
|
11
|
-
return NextResponse.json({ ok: true, recipe });
|
|
12
|
-
} catch (err: unknown) {
|
|
13
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
14
|
-
return NextResponse.json({ ok: false, error: message }, { status: 500 });
|
|
15
|
-
}
|
|
16
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
import { loadRegistry, search } from "@/lib/marketplace";
|
|
3
|
-
|
|
4
|
-
export async function GET(req: Request) {
|
|
5
|
-
try {
|
|
6
|
-
const url = new URL(req.url);
|
|
7
|
-
const q = url.searchParams.get("q");
|
|
8
|
-
const registry = await loadRegistry();
|
|
9
|
-
const recipes = search(registry.recipes, q);
|
|
10
|
-
|
|
11
|
-
return NextResponse.json({
|
|
12
|
-
ok: true,
|
|
13
|
-
version: registry.version,
|
|
14
|
-
generatedAt: registry.generatedAt,
|
|
15
|
-
count: recipes.length,
|
|
16
|
-
recipes,
|
|
17
|
-
});
|
|
18
|
-
} catch (err: unknown) {
|
|
19
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
20
|
-
return NextResponse.json({ ok: false, error: message }, { status: 500 });
|
|
21
|
-
}
|
|
22
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import crypto from "node:crypto";
|
|
2
|
-
import { NextResponse } from "next/server";
|
|
3
|
-
import { runOpenClaw } from "@/lib/openclaw";
|
|
4
|
-
import { findRecipeById, parseFrontmatterId, resolveRecipePath, writeRecipeFile } from "@/lib/recipes";
|
|
5
|
-
|
|
6
|
-
function sha256(text: string) {
|
|
7
|
-
return crypto.createHash("sha256").update(text, "utf8").digest("hex");
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export async function GET(
|
|
11
|
-
_req: Request,
|
|
12
|
-
{ params }: { params: Promise<{ id: string }> }
|
|
13
|
-
) {
|
|
14
|
-
const { id } = await params;
|
|
15
|
-
|
|
16
|
-
const item = await findRecipeById(id);
|
|
17
|
-
if (!item) return NextResponse.json({ error: `Recipe not found: ${id}` }, { status: 404 });
|
|
18
|
-
|
|
19
|
-
const shown = await runOpenClaw(["recipes", "show", id]);
|
|
20
|
-
const filePath = await resolveRecipePath(item).catch(() => null);
|
|
21
|
-
|
|
22
|
-
const recipeHash = sha256(shown.stdout);
|
|
23
|
-
|
|
24
|
-
return NextResponse.json({ recipe: { ...item, content: shown.stdout, filePath }, recipeHash, stderr: shown.stderr });
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export async function PUT(
|
|
28
|
-
req: Request,
|
|
29
|
-
{ params }: { params: Promise<{ id: string }> }
|
|
30
|
-
) {
|
|
31
|
-
const { id } = await params;
|
|
32
|
-
const body = (await req.json()) as { content?: string };
|
|
33
|
-
if (typeof body.content !== "string") {
|
|
34
|
-
return NextResponse.json({ error: "Missing content" }, { status: 400 });
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Validate frontmatter id matches route id.
|
|
38
|
-
let parsedId: string;
|
|
39
|
-
try {
|
|
40
|
-
parsedId = parseFrontmatterId(body.content);
|
|
41
|
-
} catch (e) {
|
|
42
|
-
return NextResponse.json({ error: (e as Error).message }, { status: 400 });
|
|
43
|
-
}
|
|
44
|
-
if (parsedId !== id) {
|
|
45
|
-
return NextResponse.json(
|
|
46
|
-
{ error: `Frontmatter id (${parsedId}) must match URL id (${id})` },
|
|
47
|
-
{ status: 400 }
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const item = await findRecipeById(id);
|
|
52
|
-
if (!item) return NextResponse.json({ error: `Recipe not found: ${id}` }, { status: 404 });
|
|
53
|
-
|
|
54
|
-
if (item.source === "builtin") {
|
|
55
|
-
return NextResponse.json({ error: `Recipe ${id} is builtin and cannot be modified` }, { status: 403 });
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const filePath = await resolveRecipePath(item);
|
|
59
|
-
await writeRecipeFile(filePath, body.content);
|
|
60
|
-
|
|
61
|
-
return NextResponse.json({ ok: true, filePath });
|
|
62
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { NextResponse } from "next/server";
|
|
4
|
-
import { getWorkspaceRecipesDir } from "@/lib/paths";
|
|
5
|
-
import { runOpenClaw } from "@/lib/openclaw";
|
|
6
|
-
import { suggestIds, scaffoldCmdForKind, patchFrontmatter } from "@/lib/recipe-clone";
|
|
7
|
-
|
|
8
|
-
export async function POST(req: Request) {
|
|
9
|
-
const body = (await req.json()) as {
|
|
10
|
-
fromId?: string;
|
|
11
|
-
toId?: string;
|
|
12
|
-
toName?: string;
|
|
13
|
-
overwrite?: boolean;
|
|
14
|
-
scaffold?: boolean;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const fromId = String(body.fromId ?? "").trim();
|
|
18
|
-
const toId = String(body.toId ?? "").trim();
|
|
19
|
-
const toName = typeof body.toName === "string" ? body.toName : undefined;
|
|
20
|
-
const overwrite = Boolean(body.overwrite);
|
|
21
|
-
const scaffold = Boolean(body.scaffold);
|
|
22
|
-
|
|
23
|
-
if (!fromId) return NextResponse.json({ ok: false, error: "Missing fromId" }, { status: 400 });
|
|
24
|
-
if (!toId) return NextResponse.json({ ok: false, error: "Missing toId" }, { status: 400 });
|
|
25
|
-
|
|
26
|
-
// Allow any workspace recipe id (no required prefix).
|
|
27
|
-
// Load source markdown from OpenClaw CLI (no HTTP self-call; avoids dev-server deadlocks/timeouts).
|
|
28
|
-
const shown = await runOpenClaw(["recipes", "show", fromId]);
|
|
29
|
-
if (!shown.ok) {
|
|
30
|
-
return NextResponse.json(
|
|
31
|
-
{
|
|
32
|
-
ok: false,
|
|
33
|
-
error:
|
|
34
|
-
shown.stderr.trim() ||
|
|
35
|
-
`openclaw recipes show ${fromId} failed (exit=${shown.exitCode}). Is the recipes plugin enabled?`,
|
|
36
|
-
},
|
|
37
|
-
{ status: 400 },
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const original = String(shown.stdout ?? "");
|
|
42
|
-
|
|
43
|
-
if (!original.startsWith("---\n")) throw new Error("Recipe markdown must start with YAML frontmatter (---)");
|
|
44
|
-
const { next, kind } = patchFrontmatter(original, toId, toName);
|
|
45
|
-
|
|
46
|
-
const dir = await getWorkspaceRecipesDir();
|
|
47
|
-
const filePath = path.join(dir, `${toId}.md`);
|
|
48
|
-
|
|
49
|
-
try {
|
|
50
|
-
await fs.stat(filePath);
|
|
51
|
-
if (!overwrite) {
|
|
52
|
-
return NextResponse.json(
|
|
53
|
-
{
|
|
54
|
-
ok: false,
|
|
55
|
-
error: `Recipe id already exists: ${toId}. Choose a different id (e.g. ${suggestIds(toId).join(", ")}).`,
|
|
56
|
-
code: "RECIPE_ID_TAKEN",
|
|
57
|
-
recipeId: toId,
|
|
58
|
-
suggestions: suggestIds(toId),
|
|
59
|
-
filePath,
|
|
60
|
-
},
|
|
61
|
-
{ status: 409 },
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
} catch {
|
|
65
|
-
// doesn't exist
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
69
|
-
await fs.writeFile(filePath, next, "utf8");
|
|
70
|
-
|
|
71
|
-
// Optional: scaffold workspace files immediately so "clone" yields a functional team/agent.
|
|
72
|
-
// IMPORTANT: scaffold failures should not delete/undo the cloned recipe markdown.
|
|
73
|
-
let scaffoldResult:
|
|
74
|
-
| { ok: true; stdout: string; stderr: string; exitCode: number }
|
|
75
|
-
| { ok: false; error: string; stdout: string; stderr: string; exitCode: number | null }
|
|
76
|
-
| null = null;
|
|
77
|
-
|
|
78
|
-
if (scaffold) {
|
|
79
|
-
const cmd = scaffoldCmdForKind(kind, toId);
|
|
80
|
-
|
|
81
|
-
if (!cmd) {
|
|
82
|
-
scaffoldResult = {
|
|
83
|
-
ok: false,
|
|
84
|
-
error: `Unsupported recipe kind for scaffold: ${kind || "(missing kind)"}`,
|
|
85
|
-
stdout: "",
|
|
86
|
-
stderr: "",
|
|
87
|
-
exitCode: null,
|
|
88
|
-
};
|
|
89
|
-
} else {
|
|
90
|
-
const r = await runOpenClaw(cmd);
|
|
91
|
-
if (r.ok) {
|
|
92
|
-
scaffoldResult = { ok: true, stdout: String(r.stdout ?? ""), stderr: String(r.stderr ?? ""), exitCode: r.exitCode };
|
|
93
|
-
} else {
|
|
94
|
-
scaffoldResult = {
|
|
95
|
-
ok: false,
|
|
96
|
-
error: r.stderr.trim() || `openclaw ${cmd.join(" ")} failed (exit=${r.exitCode})`,
|
|
97
|
-
stdout: String(r.stdout ?? ""),
|
|
98
|
-
stderr: String(r.stderr ?? ""),
|
|
99
|
-
exitCode: r.exitCode,
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return NextResponse.json({ ok: true, filePath, recipeId: toId, content: next, scaffold: scaffoldResult });
|
|
106
|
-
}
|