diff options
| author | YurenHao0426 <blackhao0426@gmail.com> | 2026-09-13 04:24:07 +0000 |
|---|---|---|
| committer | YurenHao0426 <blackhao0426@gmail.com> | 2026-09-13 04:24:07 +0000 |
| commit | a55e313de44444d22ef928b1bb91fd96284ea367 (patch) | |
| tree | 7273cbee484effff4878fa81a8a3313e14695aba /src/cli/main.ts | |
| parent | 55bf3f24c57521907a1bac7180aa29ea8cbf83d7 (diff) | |
Add copy command to clone Overleaf projects server-sidefix-cli-shebang
Adds `lattex-cli copy <source-id|name> <new-name>` which uses
Overleaf's POST /project/{id}/clone endpoint to create a
server-side copy of a project. Includes API method, CLI wiring,
help text, and tests.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'src/cli/main.ts')
| -rw-r--r-- | src/cli/main.ts | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/src/cli/main.ts b/src/cli/main.ts index 1fa9fce..52573fe 100644 --- a/src/cli/main.ts +++ b/src/cli/main.ts @@ -186,6 +186,37 @@ async function cmdProjects(flags: Record<string, string | boolean>): Promise<voi } } +async function cmdCopy(positional: string[], flags: Record<string, string | boolean>): Promise<void> { + const sourceRef = positional[0] + const newName = positional[1] + if (!sourceRef || !newName) { + exitWith(EXIT_USAGE, 'Usage: lattex-cli copy <source-id|name> <new-name>') + } + + const cookie = await resolveAuth(flags) + const api = new OverleafApi(cookie) + + // Resolve project ID from name if needed + let sourceId = sourceRef + if (!sourceRef.match(/^[0-9a-f]{24}$/)) { + const projects = await api.listProjects() + const match = projects.find(p => p.name === sourceRef) + if (!match) { + exitWith(EXIT_ERROR, `Project not found: ${sourceRef}`) + } + sourceId = match!.id + } + + err(`Copying project ${sourceId} as "${newName}"...`) + const newId = await api.copyProject(sourceId, newName) + + if (jsonMode) { + jsonOut({ ok: true, sourceId, newId, newName }) + } else { + out(`Copied → ${newId} "${newName}"`) + } +} + async function cmdClone(positional: string[], flags: Record<string, string | boolean>): Promise<void> { const projectRef = positional[0] const targetDir = positional[1] @@ -693,6 +724,7 @@ Commands: projects [--json] List Overleaf projects + copy <id|name> <name> Copy (clone) a project on Overleaf clone <id|name> <dir> Download project to local directory pull <dir> Update local dir from Overleaf status <dir> Show local changes @@ -726,6 +758,9 @@ async function main(): Promise<void> { case 'projects': await cmdProjects(parsed.flags) break + case 'copy': + await cmdCopy(parsed.positional, parsed.flags) + break case 'clone': await cmdClone(parsed.positional, parsed.flags) break |
