Skip to content

Commit aea1c3b

Browse files
committed
feat: add restore commands
1 parent 642c8bc commit aea1c3b

10 files changed

Lines changed: 325 additions & 36 deletions

File tree

‎README.md‎

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,79 @@
1-
# CoDev CLI
1+
# CoDev
22

3-
A CLI tool to install and configure coding agents (Claude Code, OpenCode).
3+
CoDev — AI Coding Agent Hub. Install, configure, and launch AI coding agents (Claude Code, OpenCode) from a single CLI.
44

55
## Install
66

77
```bash
8-
npm install -g codev-cli
8+
npm install -g codev-ai
99
```
1010

1111
Then run:
1212

1313
```bash
14-
codev
14+
codev install
1515
```
16+
17+
## Commands
18+
19+
| Command | What it does |
20+
| -------------------------- | ----------------------------------------------------- |
21+
| `codev` | Show version and help |
22+
| `codev --help` | Show version and help |
23+
| `codev install` | Install and configure AI coding agents |
24+
| `codev claude` | Run the `claude` CLI (forwards remaining arguments) |
25+
| `codev claude --restore` | Restore `~/.claude/` from `~/.claude.backup/` |
26+
| `codev opencode` | Run the `opencode` CLI (forwards remaining arguments) |
27+
| `codev opencode --restore` | Restore `~/.config/opencode/` from its backup |
28+
| `codev logout` | Sign out of SSO |
29+
30+
## Restoring a previous configuration
31+
32+
Before writing its own config, `codev` backs up the directory it would
33+
replace. The backup set depends on which agents you chose in Step 1:
34+
35+
| Selection | Backed up |
36+
| ----------- | --------------------- |
37+
| Claude Code | `~/.claude/` |
38+
| OpenCode | `~/.config/opencode/` |
39+
40+
If you do **not** select Claude Code, `codev` does not touch `~/.claude/` or
41+
`~/.claude.json` at all. When Claude Code **is** selected, `~/.claude.json` is
42+
read in-place and `"hasCompletedOnboarding": true` is added if missing — the
43+
file is not backed up (only that single flag is touched).
44+
45+
`settings.json` and `opencode.json` are **replaced** (not merged), so any keys
46+
you had before live only in the directory backup.
47+
48+
### Existing backups
49+
50+
If a backup already exists from a prior `codev` run (`*.backup`), `codev`
51+
pauses in Step 3 and asks whether to overwrite it — default is **No**, which
52+
keeps the existing backup (usually your original, pre-`codev` state). Answer
53+
`y` to replace it with your current contents.
54+
55+
### Restore
56+
57+
Use the built-in restore shortcut:
58+
59+
```bash
60+
codev claude --restore
61+
codev opencode --restore
62+
```
63+
64+
Each command removes the active directory and renames the corresponding
65+
`*.backup` back into place. If no backup exists, the command prints a
66+
"No backup found" message and exits with code 1.
67+
68+
Or do it manually:
69+
70+
```bash
71+
# Claude Code
72+
rm -rf ~/.claude && mv ~/.claude.backup ~/.claude
73+
74+
# OpenCode
75+
rm -rf ~/.config/opencode && mv ~/.config/opencode.backup ~/.config/opencode
76+
```
77+
78+
The restore command for each backup is also printed in the CLI after each
79+
tool is configured.

‎codev-cli/README.md‎

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# codev-ai
1+
# CoDev
22

33
CoDev — AI Coding Agent Hub. Install, configure, and launch AI coding agents (Claude Code, OpenCode) from a single CLI.
44

@@ -16,24 +16,26 @@ codev install
1616

1717
## Commands
1818

19-
| Command | What it does |
20-
| --------------- | --------------------------------------------------- |
21-
| `codev` | Show version and help |
22-
| `codev --help` | Show version and help |
23-
| `codev install` | Install and configure AI coding agents |
24-
| `codev claude` | Run the `claude` CLI (forwards remaining arguments) |
25-
| `codev opencode`| Run the `opencode` CLI (forwards remaining arguments) |
26-
| `codev logout` | Sign out of SSO |
19+
| Command | What it does |
20+
| -------------------------- | ----------------------------------------------------- |
21+
| `codev` | Show version and help |
22+
| `codev --help` | Show version and help |
23+
| `codev install` | Install and configure AI coding agents |
24+
| `codev claude` | Run the `claude` CLI (forwards remaining arguments) |
25+
| `codev claude --restore` | Restore `~/.claude/` from `~/.claude.backup/` |
26+
| `codev opencode` | Run the `opencode` CLI (forwards remaining arguments) |
27+
| `codev opencode --restore` | Restore `~/.config/opencode/` from its backup |
28+
| `codev logout` | Sign out of SSO |
2729

2830
## Restoring a previous configuration
2931

3032
Before writing its own config, `codev` backs up the directory it would
3133
replace. The backup set depends on which agents you chose in Step 1:
3234

33-
| Selection | Backed up |
34-
| ------------ | ---------------------- |
35-
| Claude Code | `~/.claude/` |
36-
| OpenCode | `~/.config/opencode/` |
35+
| Selection | Backed up |
36+
| ----------- | --------------------- |
37+
| Claude Code | `~/.claude/` |
38+
| OpenCode | `~/.config/opencode/` |
3739

3840
If you do **not** select Claude Code, `codev` does not touch `~/.claude/` or
3941
`~/.claude.json` at all. When Claude Code **is** selected, `~/.claude.json` is
@@ -52,6 +54,19 @@ keeps the existing backup (usually your original, pre-`codev` state). Answer
5254

5355
### Restore
5456

57+
Use the built-in restore shortcut:
58+
59+
```bash
60+
codev claude --restore
61+
codev opencode --restore
62+
```
63+
64+
Each command removes the active directory and renames the corresponding
65+
`*.backup` back into place. If no backup exists, the command prints a
66+
"No backup found" message and exits with code 1.
67+
68+
Or do it manually:
69+
5570
```bash
5671
# Claude Code
5772
rm -rf ~/.claude && mv ~/.claude.backup ~/.claude
@@ -60,8 +75,8 @@ rm -rf ~/.claude && mv ~/.claude.backup ~/.claude
6075
rm -rf ~/.config/opencode && mv ~/.config/opencode.backup ~/.config/opencode
6176
```
6277

63-
The exact restore command for each backup is also printed in the CLI after
64-
each tool is configured.
78+
The restore command for each backup is also printed in the CLI after each
79+
tool is configured.
6580

6681
## Development
6782

‎codev-cli/src/components/Configure.tsx‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ const LABEL: Record<BackupKind, string> = {
2727
"opencode-dir": "OpenCode",
2828
};
2929

30+
const RESTORE_CMD: Record<BackupKind, string> = {
31+
"claude-dir": "codev claude --restore",
32+
"opencode-dir": "codev opencode --restore",
33+
};
34+
3035
function scanConflicts(tools: Tool[]): Conflict[] {
3136
const out: Conflict[] = [];
3237
for (const tool of tools) {
@@ -43,9 +48,7 @@ function describeResult(r: ConfigureResult): string[] {
4348
const lines = [`Configured ${LABEL[r.kind]}`];
4449
if (r.backupPath) {
4550
lines.push(` Backup: ${r.backupPath}`);
46-
lines.push(
47-
` Restore: rm -rf ${r.sourcePath} && mv ${r.backupPath} ${r.sourcePath}`,
48-
);
51+
lines.push(` Restore: ${RESTORE_CMD[r.kind]}`);
4952
}
5053
return lines;
5154
}

‎codev-cli/src/components/Confirm.tsx‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ const CONFIG_FILE: Record<Tool, string> = {
1717
opencode: "opencode.json",
1818
};
1919

20+
const RESTORE_CMD: Record<Tool, string> = {
21+
"claude-code": "codev claude --restore",
22+
opencode: "codev opencode --restore",
23+
};
24+
2025
export function Confirm({ tools, onConfirm, readOnly = false }: ConfirmProps) {
2126
useInput(
2227
(input, key) => {
@@ -47,9 +52,7 @@ export function Confirm({ tools, onConfirm, readOnly = false }: ConfirmProps) {
4752
{` Backup: ${status.sourcePath} → ${status.backupPath}`}
4853
</Text>
4954
)}
50-
<Text>
51-
{` Restore: rm -rf ${status.sourcePath} && mv ${status.backupPath} ${status.sourcePath}`}
52-
</Text>
55+
<Text>{` Restore: ${RESTORE_CMD[tool]}`}</Text>
5356
</Box>
5457
);
5558
})}

‎codev-cli/src/help.ts‎

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
import { VERSION } from "@/const.js";
2-
31
function link(url: string): string {
42
if (!process.stdout.isTTY) return url;
53
return `\x1b]8;;${url}\x1b\\${url}\x1b]8;;\x1b\\`;
64
}
75

86
export function printHelp() {
9-
console.log(`CoDev v${VERSION} — AI Coding Agent Hub
7+
console.log(`CoDev — AI Coding Agent Hub
8+
9+
Usage: codev <command> [options]
1010
11-
Usage:
12-
codev install Install and configure AI coding agents
13-
codev claude Run the Claude Code CLI
14-
Docs: ${link("https://code.claude.com/docs/en/cli-reference")}
15-
codev opencode Run the OpenCode CLI
16-
Docs: ${link("https://opencode.ai/docs/cli/")}
17-
codev logout Sign out of SSO
18-
codev --help, -h Show this help
11+
Commands:
12+
install Install and configure AI coding agents
13+
claude Run the Claude Code CLI (${link("https://code.claude.com/docs/en/cli-reference")})
14+
claude --restore Restore ~/.claude from ~/.claude.backup
15+
opencode Run the OpenCode CLI (${link("https://opencode.ai/docs/cli/")})
16+
opencode --restore Restore ~/.config/opencode from ~/.config/opencode.backup
17+
logout Sign out of SSO
18+
--help, -h Show this help
1919
`);
2020
}

‎codev-cli/src/index.tsx‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { render } from "ink";
33
import { App } from "@/App.js";
44
import { logout } from "@/auth.js";
55
import { printHelp } from "@/help.js";
6+
import { runRestore } from "@/restore.js";
67
import { runAgent } from "@/run.js";
78

89
const [command, ...args] = process.argv.slice(2);
@@ -28,9 +29,15 @@ switch (command) {
2829
break;
2930
}
3031
case "claude":
32+
if (args[0] === "--restore") {
33+
process.exit(runRestore("claude-code"));
34+
}
3135
process.exit(await runAgent("claude", args));
3236
break;
3337
case "opencode":
38+
if (args[0] === "--restore") {
39+
process.exit(runRestore("opencode"));
40+
}
3441
process.exit(await runAgent("opencode", args));
3542
break;
3643
default:

‎codev-cli/src/restore.ts‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { restoreTool, type Tool } from "@/setup.js";
2+
3+
export function runRestore(tool: Tool): number {
4+
const result = restoreTool(tool);
5+
if (result.status === "no-backup") {
6+
console.error(`No backup found at ${result.backupPath}.`);
7+
return 1;
8+
}
9+
console.log(`Restored ${result.sourcePath} from ${result.backupPath}.`);
10+
return 0;
11+
}

‎codev-cli/src/setup.ts‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
existsSync,
55
mkdirSync,
66
readFileSync,
7+
renameSync,
78
rmSync,
89
writeFileSync,
910
} from "node:fs";
@@ -129,6 +130,29 @@ export function configureClaudeCode(
129130
return [{ kind: "claude-dir", sourcePath: dirPath, backupPath: dirBackup }];
130131
}
131132

133+
export type RestoreStatus = "restored" | "no-backup";
134+
135+
export interface RestoreResult {
136+
status: RestoreStatus;
137+
sourcePath: string;
138+
backupPath: string;
139+
}
140+
141+
export function restoreTool(tool: Tool): RestoreResult {
142+
const kind: BackupKind =
143+
tool === "claude-code" ? "claude-dir" : "opencode-dir";
144+
const sourcePath = sourcePathOf(kind);
145+
const backupPath = `${sourcePath}.backup`;
146+
147+
if (!existsSync(backupPath)) {
148+
return { status: "no-backup", sourcePath, backupPath };
149+
}
150+
151+
rmSync(sourcePath, { recursive: true, force: true });
152+
renameSync(backupPath, sourcePath);
153+
return { status: "restored", sourcePath, backupPath };
154+
}
155+
132156
export function configureOpenCode(
133157
apiKey: string,
134158
opts: ConfigureOptions = {},

0 commit comments

Comments
 (0)