MCPcopy Create free account
hub / github.com/CodeFox-Repo/codefox / forkProject

Method forkProject

backend/src/project/project.service.ts:543–605  ·  view source on GitHub ↗

* Fork an existing project to create a copy for the current user * @param userId The user ID making the request * @param projectId The project ID to fork * @returns The chat associated with the newly created project

(userId: string, projectId: string)

Source from the content-addressed store, hash-verified

541
542 try {
543 const sandbox = await sandboxHandle(newProjectId);
544 const remoteZip = '/tmp/codefox-fork.zip';
545 await sandbox.writeFiles([
546 { path: remoteZip, content: new Uint8Array(fs.readFileSync(zipPath)) },
547 ]);
548 const unpack = await sandbox.runCommand({
549 cmd: 'python3',
550 args: ['-m', 'zipfile', '-e', remoteZip, SANDBOX_ROOT],
551 timeoutMs: 5 * 60 * 1000,
552 });
553 if (unpack.exitCode !== 0) {
554 throw new Error(
555 `Unpacking the fork failed: ${(await unpack.stderr()).slice(-300)}`,
556 );
557 }
558 return newProjectId;
559 } finally {
560 fs.promises
561 .unlink(zipPath)
562 .catch((error) =>
563 this.logger.warn(`Could not remove ${zipPath}: ${error}`),
564 );
565 }
566 }
567
568 /**
569 * Your own project, copied. Same machinery as a fork — it already copies
570 * files, mints a new share id and starts private — minus the "not yours"
571 * rule, which is the only thing that ever stopped you.
572 *
573 * ponytail: a flag on forkProject, not a second copy of it. The two differ
574 * by one guard and one label.
575 */
576 async duplicateProject(userId: string, projectId: string): Promise<Chat> {
577 return this.forkProject(userId, projectId, true);
578 }
579
580 async forkProject(
581 userId: string,
582 projectId: string,
583 mine = false,
584 ): Promise<Chat> {
585 try {
586 this.logger.debug(`User ${userId} forking project ${projectId}`);
587
588 // Get the source project
589 const sourceProject = await this.getProjectById(projectId);
590
591 // Check if the project is public or owned by the requesting user
592 if (!sourceProject.isPublic && sourceProject.userId !== userId) {
593 throw new ForbiddenException(
594 'Cannot fork a private project you do not own',
595 );
596 }
597
598 // Forking someone else's is the public action; copying your own is
599 // `duplicateProject`, which sets `mine`. Without the distinction the
600 // fork button on the wall would offer a no-op on your own card.

Callers

nothing calls this directly

Calls 4

getProjectByIdMethod · 0.95
bindProjectAndChatMethod · 0.95
createChatMethod · 0.45

Tested by

no test coverage detected