@mndrk/agx 2.4.5 → 2.4.6

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.
Files changed (156) hide show
  1. package/cloud-runtime/standalone/apps/local/.next/BUILD_ID +1 -1
  2. package/cloud-runtime/standalone/apps/local/.next/build-manifest.json +2 -2
  3. package/cloud-runtime/standalone/apps/local/.next/prerender-manifest.json +3 -3
  4. package/cloud-runtime/standalone/apps/local/.next/server/app/_global-error.html +2 -2
  5. package/cloud-runtime/standalone/apps/local/.next/server/app/_global-error.rsc +1 -1
  6. package/cloud-runtime/standalone/apps/local/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  7. package/cloud-runtime/standalone/apps/local/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  8. package/cloud-runtime/standalone/apps/local/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  9. package/cloud-runtime/standalone/apps/local/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  10. package/cloud-runtime/standalone/apps/local/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  11. package/cloud-runtime/standalone/apps/local/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  12. package/cloud-runtime/standalone/apps/local/.next/server/app/_not-found.html +2 -2
  13. package/cloud-runtime/standalone/apps/local/.next/server/app/_not-found.rsc +2 -2
  14. package/cloud-runtime/standalone/apps/local/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  15. package/cloud-runtime/standalone/apps/local/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  16. package/cloud-runtime/standalone/apps/local/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  17. package/cloud-runtime/standalone/apps/local/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  18. package/cloud-runtime/standalone/apps/local/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  19. package/cloud-runtime/standalone/apps/local/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  20. package/cloud-runtime/standalone/apps/local/.next/server/app/agents/[id]/page.js.nft.json +1 -1
  21. package/cloud-runtime/standalone/apps/local/.next/server/app/agents/[id]/page_client-reference-manifest.js +1 -1
  22. package/cloud-runtime/standalone/apps/local/.next/server/app/agents/page_client-reference-manifest.js +1 -1
  23. package/cloud-runtime/standalone/apps/local/.next/server/app/agents.html +2 -2
  24. package/cloud-runtime/standalone/apps/local/.next/server/app/agents.rsc +2 -2
  25. package/cloud-runtime/standalone/apps/local/.next/server/app/agents.segments/_full.segment.rsc +2 -2
  26. package/cloud-runtime/standalone/apps/local/.next/server/app/agents.segments/_head.segment.rsc +1 -1
  27. package/cloud-runtime/standalone/apps/local/.next/server/app/agents.segments/_index.segment.rsc +2 -2
  28. package/cloud-runtime/standalone/apps/local/.next/server/app/agents.segments/_tree.segment.rsc +2 -2
  29. package/cloud-runtime/standalone/apps/local/.next/server/app/agents.segments/agents/__PAGE__.segment.rsc +1 -1
  30. package/cloud-runtime/standalone/apps/local/.next/server/app/agents.segments/agents.segment.rsc +1 -1
  31. package/cloud-runtime/standalone/apps/local/.next/server/app/index.html +2 -2
  32. package/cloud-runtime/standalone/apps/local/.next/server/app/index.rsc +2 -2
  33. package/cloud-runtime/standalone/apps/local/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  34. package/cloud-runtime/standalone/apps/local/.next/server/app/index.segments/_full.segment.rsc +2 -2
  35. package/cloud-runtime/standalone/apps/local/.next/server/app/index.segments/_head.segment.rsc +1 -1
  36. package/cloud-runtime/standalone/apps/local/.next/server/app/index.segments/_index.segment.rsc +2 -2
  37. package/cloud-runtime/standalone/apps/local/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  38. package/cloud-runtime/standalone/apps/local/.next/server/app/integrations/github/select-repos/page_client-reference-manifest.js +1 -1
  39. package/cloud-runtime/standalone/apps/local/.next/server/app/integrations/github/select-repos.html +2 -2
  40. package/cloud-runtime/standalone/apps/local/.next/server/app/integrations/github/select-repos.rsc +2 -2
  41. package/cloud-runtime/standalone/apps/local/.next/server/app/integrations/github/select-repos.segments/_full.segment.rsc +2 -2
  42. package/cloud-runtime/standalone/apps/local/.next/server/app/integrations/github/select-repos.segments/_head.segment.rsc +1 -1
  43. package/cloud-runtime/standalone/apps/local/.next/server/app/integrations/github/select-repos.segments/_index.segment.rsc +2 -2
  44. package/cloud-runtime/standalone/apps/local/.next/server/app/integrations/github/select-repos.segments/_tree.segment.rsc +2 -2
  45. package/cloud-runtime/standalone/apps/local/.next/server/app/integrations/github/select-repos.segments/integrations/github/select-repos/__PAGE__.segment.rsc +1 -1
  46. package/cloud-runtime/standalone/apps/local/.next/server/app/integrations/github/select-repos.segments/integrations/github/select-repos.segment.rsc +1 -1
  47. package/cloud-runtime/standalone/apps/local/.next/server/app/integrations/github/select-repos.segments/integrations/github.segment.rsc +1 -1
  48. package/cloud-runtime/standalone/apps/local/.next/server/app/integrations/github/select-repos.segments/integrations.segment.rsc +1 -1
  49. package/cloud-runtime/standalone/apps/local/.next/server/app/page_client-reference-manifest.js +1 -1
  50. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/automations/page.js.nft.json +1 -1
  51. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/automations/page_client-reference-manifest.js +1 -1
  52. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/env-vars/page.js.nft.json +1 -1
  53. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/env-vars/page_client-reference-manifest.js +1 -1
  54. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/folders/page.js.nft.json +1 -1
  55. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/folders/page_client-reference-manifest.js +1 -1
  56. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/graph/[taskId]/page.js.nft.json +1 -1
  57. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/graph/[taskId]/page_client-reference-manifest.js +1 -1
  58. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/notifications/page.js.nft.json +1 -1
  59. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/notifications/page_client-reference-manifest.js +1 -1
  60. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/objectives/[objectiveId]/page.js.nft.json +1 -1
  61. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/objectives/[objectiveId]/page_client-reference-manifest.js +1 -1
  62. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/objectives/page.js.nft.json +1 -1
  63. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/objectives/page_client-reference-manifest.js +1 -1
  64. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/page.js.nft.json +1 -1
  65. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
  66. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/prs/page.js.nft.json +1 -1
  67. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/prs/page_client-reference-manifest.js +1 -1
  68. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/teams/[teamId]/agents/[agentId]/page.js.nft.json +1 -1
  69. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/teams/[teamId]/agents/[agentId]/page_client-reference-manifest.js +1 -1
  70. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/teams/[teamId]/page.js.nft.json +1 -1
  71. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/teams/[teamId]/page_client-reference-manifest.js +1 -1
  72. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/teams/adopt/page.js.nft.json +1 -1
  73. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/teams/adopt/page_client-reference-manifest.js +1 -1
  74. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/teams/new/page.js.nft.json +1 -1
  75. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/teams/new/page_client-reference-manifest.js +1 -1
  76. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/teams/page.js.nft.json +1 -1
  77. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/teams/page_client-reference-manifest.js +1 -1
  78. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/teams/replace/page.js.nft.json +1 -1
  79. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/teams/replace/page_client-reference-manifest.js +1 -1
  80. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/terminal/page.js.nft.json +1 -1
  81. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/terminal/page_client-reference-manifest.js +1 -1
  82. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/thread/[threadId]/page.js.nft.json +1 -1
  83. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/thread/[threadId]/page_client-reference-manifest.js +1 -1
  84. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/tracking/[tracker]/page.js.nft.json +1 -1
  85. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/tracking/[tracker]/page_client-reference-manifest.js +1 -1
  86. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/tracking/connect/page.js.nft.json +1 -1
  87. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/tracking/connect/page_client-reference-manifest.js +1 -1
  88. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/tracking/page.js.nft.json +1 -1
  89. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/[slug]/tracking/page_client-reference-manifest.js +1 -1
  90. package/cloud-runtime/standalone/apps/local/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  91. package/cloud-runtime/standalone/apps/local/.next/server/app/projects.html +2 -2
  92. package/cloud-runtime/standalone/apps/local/.next/server/app/projects.rsc +2 -2
  93. package/cloud-runtime/standalone/apps/local/.next/server/app/projects.segments/_full.segment.rsc +2 -2
  94. package/cloud-runtime/standalone/apps/local/.next/server/app/projects.segments/_head.segment.rsc +1 -1
  95. package/cloud-runtime/standalone/apps/local/.next/server/app/projects.segments/_index.segment.rsc +2 -2
  96. package/cloud-runtime/standalone/apps/local/.next/server/app/projects.segments/_tree.segment.rsc +2 -2
  97. package/cloud-runtime/standalone/apps/local/.next/server/app/projects.segments/projects/__PAGE__.segment.rsc +1 -1
  98. package/cloud-runtime/standalone/apps/local/.next/server/app/projects.segments/projects.segment.rsc +1 -1
  99. package/cloud-runtime/standalone/apps/local/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  100. package/cloud-runtime/standalone/apps/local/.next/server/app/setup.html +2 -2
  101. package/cloud-runtime/standalone/apps/local/.next/server/app/setup.rsc +2 -2
  102. package/cloud-runtime/standalone/apps/local/.next/server/app/setup.segments/_full.segment.rsc +2 -2
  103. package/cloud-runtime/standalone/apps/local/.next/server/app/setup.segments/_head.segment.rsc +1 -1
  104. package/cloud-runtime/standalone/apps/local/.next/server/app/setup.segments/_index.segment.rsc +2 -2
  105. package/cloud-runtime/standalone/apps/local/.next/server/app/setup.segments/_tree.segment.rsc +2 -2
  106. package/cloud-runtime/standalone/apps/local/.next/server/app/setup.segments/setup/__PAGE__.segment.rsc +1 -1
  107. package/cloud-runtime/standalone/apps/local/.next/server/app/setup.segments/setup.segment.rsc +1 -1
  108. package/cloud-runtime/standalone/apps/local/.next/server/app/status/page_client-reference-manifest.js +1 -1
  109. package/cloud-runtime/standalone/apps/local/.next/server/app/status.html +2 -2
  110. package/cloud-runtime/standalone/apps/local/.next/server/app/status.rsc +2 -2
  111. package/cloud-runtime/standalone/apps/local/.next/server/app/status.segments/_full.segment.rsc +2 -2
  112. package/cloud-runtime/standalone/apps/local/.next/server/app/status.segments/_head.segment.rsc +1 -1
  113. package/cloud-runtime/standalone/apps/local/.next/server/app/status.segments/_index.segment.rsc +2 -2
  114. package/cloud-runtime/standalone/apps/local/.next/server/app/status.segments/_tree.segment.rsc +2 -2
  115. package/cloud-runtime/standalone/apps/local/.next/server/app/status.segments/status/__PAGE__.segment.rsc +1 -1
  116. package/cloud-runtime/standalone/apps/local/.next/server/app/status.segments/status.segment.rsc +1 -1
  117. package/cloud-runtime/standalone/apps/local/.next/server/chunks/ssr/[root-of-the-server]__23838f87._.js +3 -0
  118. package/cloud-runtime/standalone/apps/local/.next/server/chunks/ssr/[root-of-the-server]__a61463b8._.js +7 -0
  119. package/cloud-runtime/standalone/apps/local/.next/server/chunks/ssr/_0ecd68e8._.js +3 -0
  120. package/cloud-runtime/standalone/apps/local/.next/server/chunks/ssr/_5c140c38._.js +7 -0
  121. package/cloud-runtime/standalone/apps/local/.next/server/chunks/ssr/apps_local_30d021de._.js +3 -0
  122. package/cloud-runtime/standalone/apps/local/.next/server/chunks/ssr/apps_local_988d29c0._.js +1 -1
  123. package/cloud-runtime/standalone/apps/local/.next/server/chunks/ssr/apps_local_app_projects_[slug]_teams_[teamId]_page_tsx_6dcfdd52._.js +1 -1
  124. package/cloud-runtime/standalone/apps/local/.next/server/chunks/ssr/apps_local_components_PromptJobBoard_tsx_281b2873._.js +2 -2
  125. package/cloud-runtime/standalone/apps/local/.next/server/chunks/ssr/apps_local_components_projects_ProjectObjectivesWorkspace_tsx_751ab3d3._.js +3 -3
  126. package/cloud-runtime/standalone/apps/local/.next/server/middleware-manifest.json +5 -5
  127. package/cloud-runtime/standalone/apps/local/.next/server/pages/404.html +2 -2
  128. package/cloud-runtime/standalone/apps/local/.next/server/pages/500.html +2 -2
  129. package/cloud-runtime/standalone/apps/local/.next/server/server-reference-manifest.js +1 -1
  130. package/cloud-runtime/standalone/apps/local/.next/server/server-reference-manifest.json +1 -1
  131. package/cloud-runtime/standalone/apps/local/.next/static/chunks/692103d55fcd0328.js +5 -0
  132. package/cloud-runtime/standalone/apps/local/.next/static/chunks/{8b5d6f5bade8c4ea.js → 8d8fe711583a59f0.js} +2 -2
  133. package/cloud-runtime/standalone/apps/local/.next/static/chunks/92467c495ad08a85.js +5 -0
  134. package/cloud-runtime/standalone/apps/local/.next/static/chunks/add53c2fe147af75.css +1 -0
  135. package/cloud-runtime/standalone/apps/local/.next/static/chunks/d662272e49df1950.js +20 -0
  136. package/cloud-runtime/standalone/apps/local/.next/static/chunks/e0d68c6af17c8c87.js +1 -0
  137. package/cloud-runtime/standalone/apps/local/.next/static/chunks/{93b2b6aa0c9593f6.js → e6d4118b7c32d11c.js} +1 -1
  138. package/cloud-runtime/standalone/apps/local/app/projects/[slug]/teams/[teamId]/page.tsx +58 -2
  139. package/cloud-runtime/standalone/apps/local/components/PromptJobBoard.tsx +73 -33
  140. package/cloud-runtime/standalone/apps/local/components/projects/ObjectiveScheduledTasksPanel.tsx +78 -239
  141. package/cloud-runtime/standalone/apps/local/components/thread/WorkspaceSidebar.tsx +2 -2
  142. package/cloud-runtime/standalone/apps/local/worker/index.js +2 -2
  143. package/package.json +1 -1
  144. package/cloud-runtime/standalone/apps/local/.next/server/chunks/ssr/[root-of-the-server]__7e3c2ea1._.js +0 -7
  145. package/cloud-runtime/standalone/apps/local/.next/server/chunks/ssr/[root-of-the-server]__dbda910b._.js +0 -7
  146. package/cloud-runtime/standalone/apps/local/.next/server/chunks/ssr/_917d90b4._.js +0 -3
  147. package/cloud-runtime/standalone/apps/local/.next/server/chunks/ssr/apps_local_a2835b49._.js +0 -3
  148. package/cloud-runtime/standalone/apps/local/.next/static/chunks/55a31773f8c2833f.js +0 -20
  149. package/cloud-runtime/standalone/apps/local/.next/static/chunks/7c8515a24aeea102.js +0 -1
  150. package/cloud-runtime/standalone/apps/local/.next/static/chunks/80446e085a3aad56.css +0 -1
  151. package/cloud-runtime/standalone/apps/local/.next/static/chunks/9c29ef447bef1576.js +0 -5
  152. package/cloud-runtime/standalone/apps/local/.next/static/chunks/a9111ccc979d4933.js +0 -5
  153. package/cloud-runtime/standalone/apps/local/.next/static/chunks/d2b34ade19d9d8da.js +0 -1
  154. /package/cloud-runtime/standalone/apps/local/.next/static/{C3-tP4djbU34_g7VoIFac → fipnHmd6JPn9sTuFdYS0y}/_buildManifest.js +0 -0
  155. /package/cloud-runtime/standalone/apps/local/.next/static/{C3-tP4djbU34_g7VoIFac → fipnHmd6JPn9sTuFdYS0y}/_clientMiddlewareManifest.json +0 -0
  156. /package/cloud-runtime/standalone/apps/local/.next/static/{C3-tP4djbU34_g7VoIFac → fipnHmd6JPn9sTuFdYS0y}/_ssgManifest.js +0 -0
@@ -66,7 +66,7 @@ export default function TeamDetailPage({
66
66
 
67
67
  // Add agent
68
68
  const [showAddAgent, setShowAddAgent] = useState(false);
69
- const [addMode, setAddMode] = useState<"existing" | "preset">("existing");
69
+ const [addMode, setAddMode] = useState<"existing" | "preset" | "scratch">("existing");
70
70
  const [selectedPresetId, setSelectedPresetId] = useState<string | null>(null);
71
71
  const [selectedExistingId, setSelectedExistingId] = useState<string | null>(null);
72
72
  const [addingAgent, setAddingAgent] = useState(false);
@@ -444,9 +444,65 @@ export default function TeamDetailPage({
444
444
  >
445
445
  From Preset
446
446
  </button>
447
+ <button
448
+ onClick={() => setAddMode("scratch")}
449
+ className={`text-xs font-medium px-3 py-1.5 rounded-lg transition-colors ${
450
+ addMode === "scratch"
451
+ ? "bg-[var(--primary)] text-white"
452
+ : "bg-[var(--card-bg)] border border-[var(--border)] text-[var(--muted-foreground)]"
453
+ }`}
454
+ >
455
+ From Scratch
456
+ </button>
447
457
  </div>
448
458
 
449
- {addMode === "existing" ? (
459
+ {addMode === "scratch" ? (
460
+ <AgentForm
461
+ title="Create agent"
462
+ initial={{ name: "", role: "", provider: "claude", model: "", identity: "", skills: [], skillBindings: [] }}
463
+ submitLabel="Create & Add"
464
+ onSubmit={async (data) => {
465
+ if (!project) return;
466
+ setAddingAgent(true);
467
+ try {
468
+ const createRes = await fetch("/api/participants", {
469
+ method: "POST",
470
+ headers: { "Content-Type": "application/json" },
471
+ body: JSON.stringify({
472
+ name: data.name,
473
+ role: data.role || null,
474
+ provider: data.provider,
475
+ model: data.model || null,
476
+ color: data.color,
477
+ ...(data.identity ? { identity: data.identity } : {}),
478
+ skills: data.skills ?? [],
479
+ skillBindings: data.skillBindings ?? [],
480
+ }),
481
+ });
482
+ if (!createRes.ok) throw new Error("Failed to create agent");
483
+ const created = await createRes.json();
484
+ const agentId = created.id ?? created.participant?.id;
485
+ await fetch(`/api/projects/${project.id}/agents`, {
486
+ method: "POST",
487
+ headers: { "Content-Type": "application/json" },
488
+ body: JSON.stringify({ agentId }),
489
+ });
490
+ await fetch(`/api/projects/${project.id}/teams/${teamId}/agents`, {
491
+ method: "POST",
492
+ headers: { "Content-Type": "application/json" },
493
+ body: JSON.stringify({ agentId, roleKey: "member" }),
494
+ });
495
+ setShowAddAgent(false);
496
+ await Promise.all([fetchTeam(), fetchParticipants()]);
497
+ } catch {
498
+ /* silent */
499
+ } finally {
500
+ setAddingAgent(false);
501
+ }
502
+ }}
503
+ onCancel={() => setShowAddAgent(false)}
504
+ />
505
+ ) : addMode === "existing" ? (
450
506
  <div className="space-y-3">
451
507
  {existingAgentOptions.length === 0 ? (
452
508
  <p className="text-xs text-[var(--muted-foreground)]">
@@ -16,6 +16,7 @@ import {
16
16
  Pencil,
17
17
  User,
18
18
  Sparkles,
19
+ Search,
19
20
  } from "lucide-react";
20
21
  import { useUrlSelection } from "@/hooks/useUrlSelection";
21
22
  import { usePromptJobs } from "@/hooks/usePromptJobs";
@@ -133,7 +134,7 @@ function SectionLabel({ children }: { children: React.ReactNode }) {
133
134
 
134
135
  // ── Create/Edit Modal ────────────────────────────────────────────────────────
135
136
 
136
- interface AgentOption {
137
+ export interface AgentOption {
137
138
  id: string;
138
139
  name: string;
139
140
  provider: string;
@@ -163,12 +164,12 @@ function Label({ children }: { children: React.ReactNode }) {
163
164
  );
164
165
  }
165
166
 
166
- function agentAvatar(id: string, color: string, size = 24) {
167
+ export function agentAvatar(id: string, color: string, size = 24) {
167
168
  const bg = color ? color.replace("#", "") : "e2e8f0";
168
169
  return `https://api.dicebear.com/9.x/bottts-neutral/svg?seed=${encodeURIComponent(id)}&size=${size}&backgroundColor=${bg}`;
169
170
  }
170
171
 
171
- function AgentDropdown({
172
+ export function AgentDropdown({
172
173
  agents,
173
174
  value,
174
175
  onChange,
@@ -178,8 +179,23 @@ function AgentDropdown({
178
179
  onChange: (id: string) => void;
179
180
  }) {
180
181
  const [open, setOpen] = useState(false);
182
+ const [query, setQuery] = useState("");
181
183
  const selected = agents.find((a) => a.id === value);
182
184
 
185
+ useEffect(() => {
186
+ if (!open) setQuery("");
187
+ }, [open]);
188
+
189
+ const q = query.trim().toLowerCase();
190
+ const filteredAgents = q
191
+ ? agents.filter(
192
+ (a) =>
193
+ a.name.toLowerCase().includes(q) ||
194
+ a.provider.toLowerCase().includes(q) ||
195
+ (a.model ?? "").toLowerCase().includes(q)
196
+ )
197
+ : agents;
198
+
183
199
  return (
184
200
  <div className="relative">
185
201
  <Label>Agent</Label>
@@ -217,38 +233,62 @@ function AgentDropdown({
217
233
  </button>
218
234
 
219
235
  {open && (
220
- <div className="absolute z-20 mt-1 w-full rounded-lg border border-[var(--card-border)] bg-[var(--card-bg)] shadow-lg max-h-[280px] overflow-y-auto">
221
- {agents.map((a) => (
222
- <button
223
- key={a.id}
224
- type="button"
225
- onClick={() => {
226
- onChange(a.id);
227
- setOpen(false);
228
- }}
229
- className={`w-full flex items-center gap-2.5 px-3 py-2.5 text-left transition-colors hover:bg-[var(--muted)] ${value === a.id ? "bg-[var(--muted)]" : ""}`}
230
- >
231
- <img
232
- src={agentAvatar(a.id, a.color)}
233
- alt=""
234
- className="size-6 rounded-full shrink-0"
236
+ <div className="absolute z-20 mt-1 w-full rounded-lg border border-[var(--card-border)] bg-[var(--card-bg)] shadow-lg flex flex-col max-h-[320px]">
237
+ <div className="sticky top-0 shrink-0 border-b border-[var(--card-border)] bg-[var(--card-bg)] px-2 py-2">
238
+ <div className="relative">
239
+ <Search
240
+ size={12}
241
+ className="absolute left-2.5 top-1/2 -translate-y-1/2 text-[var(--muted-foreground)]"
235
242
  />
236
- <div className="min-w-0 flex-1">
237
- <div className="text-xs font-medium text-[var(--foreground)] truncate">
238
- {a.name}
239
- </div>
240
- <div className="text-[10px] text-[var(--muted-foreground)]">
241
- {a.provider}
242
- {a.model ? ` / ${a.model}` : ""}
243
- </div>
243
+ <input
244
+ type="text"
245
+ value={query}
246
+ onChange={(e) => setQuery(e.target.value)}
247
+ autoFocus
248
+ placeholder="Search agents..."
249
+ className="w-full rounded-md border border-[var(--card-border)] bg-[var(--muted)] pl-7 pr-2 py-1.5 text-xs text-[var(--foreground)] placeholder:text-[var(--muted-foreground)] focus:outline-none focus:border-[var(--foreground)]"
250
+ />
251
+ </div>
252
+ </div>
253
+ <div className="min-h-0 flex-1 overflow-y-auto">
254
+ {filteredAgents.length === 0 ? (
255
+ <div className="px-3 py-4 text-center text-[11px] text-[var(--muted-foreground)]">
256
+ No agents match "{query}"
244
257
  </div>
245
- {value === a.id && (
246
- <span className="text-xs text-[var(--foreground)]">
247
- &#10003;
248
- </span>
249
- )}
250
- </button>
251
- ))}
258
+ ) : (
259
+ filteredAgents.map((a) => (
260
+ <button
261
+ key={a.id}
262
+ type="button"
263
+ onClick={() => {
264
+ onChange(a.id);
265
+ setOpen(false);
266
+ }}
267
+ className={`w-full flex items-center gap-2.5 px-3 py-2.5 text-left transition-colors hover:bg-[var(--muted)] ${value === a.id ? "bg-[var(--muted)]" : ""}`}
268
+ >
269
+ <img
270
+ src={agentAvatar(a.id, a.color)}
271
+ alt=""
272
+ className="size-6 rounded-full shrink-0"
273
+ />
274
+ <div className="min-w-0 flex-1">
275
+ <div className="text-xs font-medium text-[var(--foreground)] truncate">
276
+ {a.name}
277
+ </div>
278
+ <div className="text-[10px] text-[var(--muted-foreground)]">
279
+ {a.provider}
280
+ {a.model ? ` / ${a.model}` : ""}
281
+ </div>
282
+ </div>
283
+ {value === a.id && (
284
+ <span className="text-xs text-[var(--foreground)]">
285
+ &#10003;
286
+ </span>
287
+ )}
288
+ </button>
289
+ ))
290
+ )}
291
+ </div>
252
292
  </div>
253
293
  )}
254
294
  </div>
@@ -1,14 +1,17 @@
1
1
  "use client";
2
2
 
3
3
  import { useCallback, useEffect, useMemo, useState } from "react";
4
- import { Check, Clock, Pause, Play, Plus, Trash2, X, XCircle } from "lucide-react";
4
+ import { Check, Clock, Pause, Pencil, Play, Plus, Terminal, Trash2, XCircle } from "lucide-react";
5
5
  import { usePromptJobs } from "@/hooks/usePromptJobs";
6
6
  import { cronToHuman } from "@/src/graph/nl-schedule";
7
7
  import type { PromptJob, PromptRun } from "@/src/prompt-scheduler/types";
8
- import { CreateJobModal, type CreateJobData } from "@/components/PromptJobBoard";
8
+ import {
9
+ CreateJobModal,
10
+ agentAvatar,
11
+ type AgentOption,
12
+ type CreateJobData,
13
+ } from "@/components/PromptJobBoard";
9
14
  import ConfirmDialog from "@/components/ConfirmDialog";
10
- import RichTextEditor from "@/components/RichTextEditor";
11
- import { ScheduleConditionPicker } from "@/components/scheduling/ScheduleConditionPicker";
12
15
 
13
16
  export type ObjectiveScheduledTaskDraft = CreateJobData;
14
17
 
@@ -51,14 +54,6 @@ function formatNextRun(epochMs: number | null, state: PromptJob["state"]): strin
51
54
  return `in ${Math.round(diff / 86_400_000)}d`;
52
55
  }
53
56
 
54
- function promptSummary(prompt: string): string {
55
- const firstLine = prompt
56
- .split("\n")
57
- .map((line) => line.trim())
58
- .find(Boolean);
59
- return firstLine || "No instructions yet";
60
- }
61
-
62
57
  function formatDateTime(value: string): string {
63
58
  const date = new Date(value);
64
59
  return date.toLocaleString(undefined, {
@@ -69,186 +64,6 @@ function formatDateTime(value: string): string {
69
64
  });
70
65
  }
71
66
 
72
- function ScheduleEditModal({
73
- job,
74
- onClose,
75
- onUpdate,
76
- }: {
77
- job: PromptJob;
78
- onClose: () => void;
79
- onUpdate: (updates: Partial<PromptJob>) => Promise<boolean>;
80
- }) {
81
- const [scheduleValue, setScheduleValue] = useState({
82
- cadence: job.cronExpr || job.cadence || "",
83
- condition: job.condition || "",
84
- });
85
- const [isValid, setIsValid] = useState(true);
86
- const [saving, setSaving] = useState(false);
87
-
88
- const handleSave = async () => {
89
- if (!isValid) return;
90
- setSaving(true);
91
- const ok = await onUpdate({
92
- cadence: scheduleValue.cadence,
93
- condition: scheduleValue.condition,
94
- } as Partial<PromptJob>);
95
- setSaving(false);
96
- if (ok) {
97
- onClose();
98
- }
99
- };
100
-
101
- return (
102
- <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 px-4 py-6">
103
- <div className="flex w-full max-w-md max-h-[85vh] flex-col rounded-[28px] border border-[var(--border)] bg-[var(--card-bg)] shadow-2xl">
104
- <div className="flex shrink-0 items-center justify-between border-b border-[var(--border)] px-6 py-4">
105
- <div className="flex items-center gap-2.5">
106
- <Clock className="h-4 w-4 text-[var(--muted-foreground)]" />
107
- <p className="text-sm font-semibold text-[var(--foreground)]">{job.name}</p>
108
- </div>
109
- <button
110
- type="button"
111
- onClick={onClose}
112
- className="rounded-lg border border-[var(--border)] p-2 text-[var(--muted-foreground)] transition-colors hover:border-[var(--card-hover-border)] hover:text-[var(--foreground)]"
113
- >
114
- <X className="h-4 w-4" />
115
- </button>
116
- </div>
117
-
118
- <div className="min-h-0 flex-1 overflow-y-auto px-6 py-5">
119
- <ScheduleConditionPicker
120
- value={scheduleValue}
121
- onChange={(next, meta) => {
122
- setScheduleValue(next);
123
- setIsValid(meta.isScheduleValid);
124
- }}
125
- scheduleLabel="Schedule"
126
- conditionLabel="Condition"
127
- conditionHelpText="Scheduled runs and Run now will check this condition before executing."
128
- />
129
- </div>
130
-
131
- <div className="flex shrink-0 items-center justify-end gap-3 border-t border-[var(--border)] px-6 py-4">
132
- <button
133
- type="button"
134
- onClick={onClose}
135
- className="rounded-xl border border-[var(--border)] px-4 py-2.5 text-sm text-[var(--foreground)] transition-colors hover:border-[var(--card-hover-border)]"
136
- >
137
- Cancel
138
- </button>
139
- <button
140
- type="button"
141
- onClick={() => void handleSave()}
142
- disabled={saving || !isValid}
143
- className="rounded-xl border border-emerald-500/30 bg-emerald-500/10 px-4 py-2.5 text-sm text-emerald-400 transition-colors hover:bg-emerald-500/20 disabled:opacity-50"
144
- >
145
- {saving ? "Saving..." : "Save"}
146
- </button>
147
- </div>
148
- </div>
149
- </div>
150
- );
151
- }
152
-
153
- function ObjectiveScheduledTaskDetailModal({
154
- job,
155
- onClose,
156
- onUpdate,
157
- }: {
158
- job: PromptJob;
159
- onClose: () => void;
160
- onUpdate: (updates: Partial<PromptJob>) => Promise<boolean>;
161
- }) {
162
- const [promptDraft, setPromptDraft] = useState(job.prompt || "");
163
- const [saving, setSaving] = useState(false);
164
-
165
- const savePrompt = async () => {
166
- if (promptDraft === job.prompt) return;
167
- setSaving(true);
168
- await onUpdate({ prompt: promptDraft } as Partial<PromptJob>);
169
- setSaving(false);
170
- };
171
-
172
- return (
173
- <div className="fixed inset-0 z-40 flex items-center justify-center bg-black/50 px-4 py-6">
174
- <div className="flex w-full max-w-6xl max-h-[85vh] flex-col rounded-[28px] border border-[var(--border)] bg-[var(--card-bg)] shadow-2xl">
175
- {/* Header */}
176
- <div className="flex shrink-0 items-start justify-between gap-4 border-b border-[var(--border)] px-6 py-5">
177
- <div className="min-w-0">
178
- <div className="flex flex-wrap items-center gap-2.5">
179
- <p className="truncate text-lg font-semibold text-[var(--foreground)]">
180
- {job.name}
181
- </p>
182
- <span
183
- className={`rounded-full border px-2 py-0.5 text-[10px] font-semibold uppercase tracking-[0.16em] ${stateClasses(job.state)}`}
184
- >
185
- {formatState(job.state)}
186
- </span>
187
- {job.condition ? (
188
- <span className="rounded-md border border-blue-400/20 bg-blue-500/10 px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wider text-blue-400">
189
- gated
190
- </span>
191
- ) : null}
192
- </div>
193
- <div className="mt-2 flex flex-wrap items-center gap-3 text-xs text-[var(--muted-foreground)]">
194
- <span className="inline-flex items-center gap-1.5">
195
- <Clock className="h-3.5 w-3.5" />
196
- {formatCadence(job)}
197
- </span>
198
- <span>Next run {formatNextRun(job.nextRunAt, job.state)}</span>
199
- <span>Updated {formatDateTime(job.updatedAt)}</span>
200
- </div>
201
- </div>
202
- <button
203
- type="button"
204
- onClick={onClose}
205
- className="rounded-lg border border-[var(--border)] p-2 text-[var(--muted-foreground)] transition-colors hover:border-[var(--card-hover-border)] hover:text-[var(--foreground)]"
206
- aria-label="Close scheduled task details"
207
- >
208
- <X className="h-4 w-4" />
209
- </button>
210
- </div>
211
-
212
- {/* Scrollable editor area */}
213
- <div className="min-h-0 flex-1 overflow-y-auto px-6 py-6 space-y-5">
214
- <div>
215
- <p className="mb-2 text-xs font-semibold uppercase tracking-[0.18em] text-[var(--muted-foreground)]">
216
- Instructions
217
- </p>
218
- <div className="rounded-2xl border border-[var(--card-hover-border)] bg-[var(--overlay-panel-muted)] px-1 py-1 text-sm leading-6 text-[var(--foreground)]">
219
- <RichTextEditor
220
- content={promptDraft}
221
- editable
222
- onChange={setPromptDraft}
223
- placeholder="Write instructions in markdown…"
224
- />
225
- </div>
226
- </div>
227
- </div>
228
-
229
- {/* Sticky footer */}
230
- <div className="flex shrink-0 items-center justify-end gap-3 border-t border-[var(--border)] px-6 py-4">
231
- <button
232
- type="button"
233
- onClick={onClose}
234
- className="rounded-xl border border-[var(--border)] px-4 py-2.5 text-sm text-[var(--foreground)] transition-colors hover:border-[var(--card-hover-border)]"
235
- >
236
- Cancel
237
- </button>
238
- <button
239
- type="button"
240
- onClick={() => void savePrompt()}
241
- disabled={saving}
242
- className="rounded-xl border border-emerald-500/30 bg-emerald-500/10 px-4 py-2.5 text-sm text-emerald-400 transition-colors hover:bg-emerald-500/20 disabled:opacity-50"
243
- >
244
- {saving ? "Saving..." : "Save"}
245
- </button>
246
- </div>
247
- </div>
248
- </div>
249
- );
250
- }
251
-
252
67
  function formatState(state: PromptJob["state"]): string {
253
68
  if (state === "active") return "Active";
254
69
  if (state === "paused") return "Paused";
@@ -280,10 +95,21 @@ export function ObjectiveScheduledTasksPanel({
280
95
  const [showCreate, setShowCreate] = useState(false);
281
96
  const [busyId, setBusyId] = useState<string | null>(null);
282
97
  const [error, setError] = useState<string | null>(null);
283
- const [selectedJobId, setSelectedJobId] = useState<string | null>(null);
98
+ const [editingJobId, setEditingJobId] = useState<string | null>(null);
284
99
  const [deleteTarget, setDeleteTarget] = useState<PromptJob | null>(null);
285
- const [scheduleEditJobId, setScheduleEditJobId] = useState<string | null>(null);
286
100
  const [recentRuns, setRecentRuns] = useState<(PromptRun & { jobName: string })[]>([]);
101
+ const [agentMap, setAgentMap] = useState<Record<string, AgentOption>>({});
102
+
103
+ useEffect(() => {
104
+ fetch("/api/prompt-jobs/agents")
105
+ .then((r) => r.json())
106
+ .then((d) => {
107
+ const map: Record<string, AgentOption> = {};
108
+ for (const a of (d.agents ?? []) as AgentOption[]) map[a.id] = a;
109
+ setAgentMap(map);
110
+ })
111
+ .catch((err) => console.warn("[ObjectiveScheduledTasksPanel] fetch agents failed:", err));
112
+ }, []);
287
113
 
288
114
  const visibleJobs = useMemo(() => {
289
115
  const filtered = jobs.filter((job) => job.objectiveId === objectiveId);
@@ -294,9 +120,10 @@ export function ObjectiveScheduledTasksPanel({
294
120
  return aPin - bPin;
295
121
  });
296
122
  }, [jobs, objectiveId]);
297
- const selectedJob = useMemo(
298
- () => visibleJobs.find((job) => job.id === selectedJobId) ?? null,
299
- [selectedJobId, visibleJobs]
123
+
124
+ const editingJob = useMemo(
125
+ () => visibleJobs.find((job) => job.id === editingJobId) ?? null,
126
+ [editingJobId, visibleJobs]
300
127
  );
301
128
 
302
129
  const loadRecentRuns = useCallback(async () => {
@@ -334,9 +161,6 @@ export function ObjectiveScheduledTasksPanel({
334
161
  setError(result.error ?? `Failed to hide "${job.name}".`);
335
162
  return;
336
163
  }
337
- if (selectedJobId === job.id) {
338
- setSelectedJobId(null);
339
- }
340
164
  await refresh();
341
165
  };
342
166
 
@@ -349,16 +173,10 @@ export function ObjectiveScheduledTasksPanel({
349
173
  return ok;
350
174
  };
351
175
 
352
- const scheduleEditJob = useMemo(
353
- () => visibleJobs.find((job) => job.id === scheduleEditJobId) ?? null,
354
- [scheduleEditJobId, visibleJobs]
355
- );
356
-
357
- const handleJobUpdate = useCallback(
358
- async (jobId: string, updates: Partial<PromptJob>) => {
359
- const ok = await updateJob(jobId, updates);
176
+ const handleEditSubmit = useCallback(
177
+ async (jobId: string, data: CreateJobData) => {
178
+ const ok = await updateJob(jobId, data as Partial<PromptJob>);
360
179
  if (ok) {
361
- setSelectedJobId(jobId);
362
180
  await refresh();
363
181
  }
364
182
  return ok;
@@ -369,28 +187,32 @@ export function ObjectiveScheduledTasksPanel({
369
187
  return (
370
188
  <>
371
189
  {showCreate ? (
372
- <CreateJobModal
373
- onClose={() => setShowCreate(false)}
374
- onSubmit={async (data) => {
375
- await handleCreate(data);
376
- }}
377
- createDefaults={createDefaults}
378
- contextLabel={objectiveKey}
379
- />
380
- ) : null}
381
- {selectedJob ? (
382
- <ObjectiveScheduledTaskDetailModal
383
- job={selectedJob}
384
- onClose={() => setSelectedJobId(null)}
385
- onUpdate={(updates) => handleJobUpdate(selectedJob.id, updates)}
386
- />
190
+ <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 px-4 py-6">
191
+ <div className="w-full max-w-5xl h-[85vh] overflow-hidden rounded-[28px] border border-[var(--border)] bg-[var(--card-bg)] shadow-2xl">
192
+ <CreateJobModal
193
+ onClose={() => setShowCreate(false)}
194
+ onSubmit={async (data) => {
195
+ await handleCreate(data);
196
+ }}
197
+ createDefaults={createDefaults}
198
+ contextLabel={objectiveKey}
199
+ />
200
+ </div>
201
+ </div>
387
202
  ) : null}
388
- {scheduleEditJob ? (
389
- <ScheduleEditModal
390
- job={scheduleEditJob}
391
- onClose={() => setScheduleEditJobId(null)}
392
- onUpdate={(updates) => handleJobUpdate(scheduleEditJob.id, updates)}
393
- />
203
+ {editingJob ? (
204
+ <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 px-4 py-6">
205
+ <div className="w-full max-w-5xl h-[85vh] overflow-hidden rounded-[28px] border border-[var(--border)] bg-[var(--card-bg)] shadow-2xl">
206
+ <CreateJobModal
207
+ onClose={() => setEditingJobId(null)}
208
+ onSubmit={async (data) => {
209
+ await handleEditSubmit(editingJob.id, data);
210
+ }}
211
+ editingJob={editingJob}
212
+ contextLabel={objectiveKey}
213
+ />
214
+ </div>
215
+ </div>
394
216
  ) : null}
395
217
 
396
218
  <div className="px-1">
@@ -431,11 +253,11 @@ export function ObjectiveScheduledTasksPanel({
431
253
  visibleJobs.map((job) => (
432
254
  <div
433
255
  key={job.id}
434
- onClick={() => setSelectedJobId(job.id)}
256
+ onClick={() => setEditingJobId(job.id)}
435
257
  onKeyDown={(event) => {
436
258
  if (event.key === "Enter" || event.key === " ") {
437
259
  event.preventDefault();
438
- setSelectedJobId(job.id);
260
+ setEditingJobId(job.id);
439
261
  }
440
262
  }}
441
263
  role="button"
@@ -488,9 +310,27 @@ export function ObjectiveScheduledTasksPanel({
488
310
  </span>
489
311
  ) : null}
490
312
  </div>
491
- <p className="mt-3 line-clamp-2 text-sm leading-6 text-[var(--muted-foreground)]">
492
- {promptSummary(job.prompt)}
493
- </p>
313
+ <div className="mt-3 flex items-center gap-2 min-w-0 text-xs text-[var(--muted-foreground)]">
314
+ {job.agentId && agentMap[job.agentId] ? (
315
+ <img
316
+ src={agentAvatar(job.agentId, agentMap[job.agentId].color, 20)}
317
+ alt=""
318
+ className="size-5 rounded-full shrink-0"
319
+ />
320
+ ) : (
321
+ <Terminal className="h-3.5 w-3.5 shrink-0" />
322
+ )}
323
+ <span className="truncate font-medium text-[var(--foreground)]">
324
+ {job.agentId && agentMap[job.agentId]
325
+ ? agentMap[job.agentId].name
326
+ : job.provider}
327
+ </span>
328
+ {job.model ? (
329
+ <span className="truncate font-mono text-[11px]">
330
+ {job.model}
331
+ </span>
332
+ ) : null}
333
+ </div>
494
334
  {job.condition ? (
495
335
  <p className="mt-2 text-xs text-[var(--muted-foreground)]">
496
336
  Condition: {job.condition}
@@ -504,7 +344,6 @@ export function ObjectiveScheduledTasksPanel({
504
344
  title="Run now"
505
345
  onClick={async (event) => {
506
346
  event.stopPropagation();
507
- setSelectedJobId(job.id);
508
347
  setBusyId(job.id);
509
348
  await runNow(job.id);
510
349
  setBusyId(null);
@@ -518,14 +357,14 @@ export function ObjectiveScheduledTasksPanel({
518
357
  </button>
519
358
  <button
520
359
  type="button"
521
- title="Edit schedule"
360
+ title="Edit"
522
361
  onClick={(event) => {
523
362
  event.stopPropagation();
524
- setScheduleEditJobId(job.id);
363
+ setEditingJobId(job.id);
525
364
  }}
526
365
  className="rounded-lg border border-[var(--border)] p-2 text-[var(--muted-foreground)] transition-colors hover:border-sky-400/40 hover:text-sky-300"
527
366
  >
528
- <Clock className="h-3.5 w-3.5" />
367
+ <Pencil className="h-3.5 w-3.5" />
529
368
  </button>
530
369
  <button
531
370
  type="button"
@@ -981,11 +981,11 @@ export function WorkspaceSidebar({
981
981
  </div>
982
982
  </div>
983
983
 
984
- {/* Work group — visible from stage 2+ */}
984
+ {/* Automation group — visible from stage 2+ */}
985
985
  {showWorkGroup && (
986
986
  <div className="mb-3">
987
987
  <div className="workspace-sidebar__section-header">
988
- <p className="workspace-sidebar__section-label">Work</p>
988
+ <p className="workspace-sidebar__section-label">Automation</p>
989
989
  </div>
990
990
  <div className="px-2 flex flex-col gap-0.5">
991
991
  {stageShow.objectives && (