MCPcopy
hub / github.com/nowork-studio/NotFair / cloneAgent

Function cloneAgent

notfair-cmo/src/server/agents/clone.ts:44–118  ·  view source on GitHub ↗
(input: CloneAgentInput)

Source from the content-addressed store, hash-verified

42 * forward — the new agent starts with an empty thread list).
43 */
44export async function cloneAgent(input: CloneAgentInput): Promise<CloneAgentResult> {
45 let newSlug: string;
46 if (input.slug_is_canonical) {
47 if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(input.new_slug)) {
48 throw new Error(`Invalid canonical slug: ${input.new_slug}`);
49 }
50 newSlug = input.new_slug;
51 } else {
52 const slugResult = slugify(input.new_slug);
53 if (!slugResult.ok) {
54 throw new Error(`Invalid agent slug: ${slugResult.reason}`);
55 }
56 newSlug = slugResult.slug;
57 }
58 const newAgentId = `${input.project_slug}-${newSlug}`;
59 if (agentExistsInProject(input.project_slug, newSlug)) {
60 throw new Error(
61 `An agent named "${newSlug}" already exists in this project. Pick a different name.`,
62 );
63 }
64
65 const srcDir = workspaceDirFor(input.source_agent_id);
66 const dstDir = workspaceDirFor(newAgentId);
67 let filesCopied = 0;
68 if (existsSync(srcDir)) {
69 await cp(srcDir, dstDir, { recursive: true });
70 filesCopied = 1; // we don't enumerate; the dir is intact
71 }
72
73 // Clone scheduled jobs.
74 const srcJobs = listAgentScheduledJobs(input.project_slug, input.source_agent_id);
75 const sourceCrons: CloneSourceCron[] = srcJobs.map((j) => ({
76 id: j.id,
77 name: j.name,
78 disabled: j.enabled === 0,
79 }));
80 const newCronIds: string[] = [];
81 for (const j of srcJobs) {
82 try {
83 const cloned = createScheduledJob({
84 project_slug: input.project_slug,
85 agent_id: newAgentId,
86 name: j.name,
87 cron_expr: j.cron_expr,
88 message: j.message,
89 enabled: j.enabled === 1,
90 });
91 newCronIds.push(cloned.id);
92 } catch (err) {
93 console.error("[clone] failed to copy cron:", err);
94 }
95 }
96
97 const displayName = (input.display_name ?? input.source_agent_id).trim() || input.source_agent_id;
98 const sourceMeta = readAgentMeta(input.source_agent_id);
99 await writeAgentMeta({
100 agent_id: newAgentId,
101 project_slug: input.project_slug,

Callers 2

cloneAgentActionFunction · 0.90
relocateAgentFunction · 0.90

Calls 7

slugifyFunction · 0.90
workspaceDirForFunction · 0.90
listAgentScheduledJobsFunction · 0.90
createScheduledJobFunction · 0.90
readAgentMetaFunction · 0.90
writeAgentMetaFunction · 0.90
agentExistsInProjectFunction · 0.85

Tested by

no test coverage detected