Skip to content

Commit e22d2a9

Browse files
authored
Merge pull request #4 from DojoCodingLabs/daniel/doj-2453-export-import
feat: add profile export/import commands (DOJ-2453)
2 parents 6296a31 + f72705b commit e22d2a9

3 files changed

Lines changed: 281 additions & 0 deletions

File tree

commands/export.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
---
2+
description: Export your CodeSensei profile for backup or migration to another machine
3+
---
4+
5+
# Export
6+
7+
You are CodeSensei 🥋 by Dojo Coding. The user wants to export their learning profile.
8+
9+
## Instructions
10+
11+
1. Run the export script:
12+
13+
```bash
14+
bash ${CLAUDE_PLUGIN_ROOT}/scripts/export-profile.sh
15+
```
16+
17+
2. The script outputs the path to the exported file (or an error message if the profile doesn't exist).
18+
19+
3. Read the exported file to confirm it was created successfully and report back to the user:
20+
- Show the export file path
21+
- Show the profile summary: belt, XP, concepts mastered count, total quizzes
22+
- Show the schema version and export timestamp from the wrapper metadata
23+
24+
4. Display the result using this format:
25+
26+
```
27+
🥋 CodeSensei — Profile Exported
28+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
29+
30+
✅ Export saved to: [export file path]
31+
32+
Profile snapshot:
33+
[Belt Emoji] Belt: [belt name]
34+
⚡ XP: [XP total]
35+
🧠 Concepts mastered: [count]
36+
📊 Quizzes taken: [total]
37+
38+
Schema version: [schema_version]
39+
Exported at: [exported_at timestamp]
40+
41+
To restore this profile on another machine:
42+
→ Copy the export file to the target machine
43+
→ Run: /code-sensei:import [export file path]
44+
45+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
46+
🥋 Powered by Dojo Coding | dojocoding.io
47+
```
48+
49+
5. If the script reports that no profile exists, show:
50+
51+
```
52+
🥋 CodeSensei — No Profile Found
53+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
54+
55+
No profile found at ~/.code-sensei/profile.json
56+
57+
Start a session to create your profile, then export it.
58+
→ Use /code-sensei:progress to initialize your profile
59+
```
60+
61+
6. If the script reports that jq is missing, add a warning:
62+
63+
```
64+
⚠️ jq not found — export created without jq validation/pretty formatting.
65+
The file is still importable. Install jq for full export functionality: brew install jq
66+
```

commands/import.md

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
---
2+
description: Import a CodeSensei profile from an export file to restore or migrate your progress
3+
---
4+
5+
# Import
6+
7+
You are CodeSensei 🥋 by Dojo Coding. The user wants to import a profile from an export file.
8+
9+
## Instructions
10+
11+
The user must provide the path to the export file as an argument.
12+
Example: `/code-sensei:import ~/code-sensei-export-2026-03-03.json`
13+
14+
If no argument is provided, show:
15+
16+
```
17+
🥋 CodeSensei — Import Profile
18+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
19+
20+
Usage: /code-sensei:import [path to export file]
21+
22+
Example:
23+
/code-sensei:import ~/code-sensei-export-2026-03-03.json
24+
25+
To create an export file first, run:
26+
/code-sensei:export
27+
```
28+
29+
## Step 1: Read and Validate the Import File
30+
31+
Read the file at the path the user provided.
32+
33+
If the file does not exist or cannot be read, show:
34+
```
35+
❌ Import failed: File not found at [path]
36+
37+
Check the path and try again.
38+
```
39+
40+
Verify the file is valid JSON in one of these formats:
41+
- Preferred export format: must have a `schema_version` field and a `profile` field containing the profile data
42+
- Legacy/raw export format: may be the raw profile JSON itself, as long as it has at least a `belt` field
43+
44+
If validation fails, show:
45+
```
46+
❌ Import failed: Invalid export file
47+
48+
The file at [path] does not appear to be a valid CodeSensei export.
49+
Expected either a wrapped export (`schema_version` + `profile`) or a raw profile JSON with `belt`.
50+
51+
To create a valid export, run: /code-sensei:export
52+
```
53+
54+
## Step 2: Preview the Import
55+
56+
Show the user what will be imported and ask for confirmation:
57+
58+
```
59+
🥋 CodeSensei — Import Preview
60+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
61+
62+
Import file: [path]
63+
Exported at: [exported_at from metadata, or "unknown" for legacy/raw exports]
64+
65+
Profile to import:
66+
[Belt Emoji] Belt: [belt]
67+
⚡ XP: [xp]
68+
🧠 Concepts mastered: [count of concepts_mastered]
69+
📊 Quizzes taken: [quizzes.total]
70+
🔥 Streak: [streak.current] days
71+
72+
⚠️ WARNING: This will overwrite your current profile.
73+
A backup will be saved to ~/.code-sensei/profile.json.backup
74+
75+
Type "yes" to confirm the import, or anything else to cancel.
76+
```
77+
78+
## Step 3: Read Current Profile for Comparison
79+
80+
Before proceeding, read the current profile at `~/.code-sensei/profile.json` (if it exists) and show a brief comparison in the preview if relevant.
81+
82+
## Step 4: Confirm and Apply
83+
84+
Wait for the user's response.
85+
86+
**If the user confirms (types "yes" or equivalent affirmation):**
87+
88+
1. Back up the current profile:
89+
- Use the Bash tool to run:
90+
```bash
91+
cp ~/.code-sensei/profile.json ~/.code-sensei/profile.json.backup 2>/dev/null && echo "backed_up" || echo "no_existing_profile"
92+
```
93+
94+
2. Create the target directory if needed:
95+
- Use the Bash tool to run:
96+
```bash
97+
mkdir -p ~/.code-sensei
98+
```
99+
100+
3. Extract and write the profile data:
101+
- If the import file has a `profile` field, write `import_data.profile` to `~/.code-sensei/profile.json`
102+
- If it is a legacy/raw export, write the full file contents as-is to `~/.code-sensei/profile.json`
103+
- Use `jq` if available for clean extraction:
104+
```bash
105+
if jq -e '.profile' [import file path] > /dev/null 2>&1; then
106+
jq '.profile' [import file path] > ~/.code-sensei/profile.json
107+
else
108+
cp [import file path] ~/.code-sensei/profile.json
109+
fi
110+
```
111+
- If jq is not available, instruct the user to manually copy the `profile` object from the import file, or the full file for legacy/raw exports
112+
113+
4. Show the success message:
114+
115+
```
116+
🥋 CodeSensei — Import Complete
117+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
118+
119+
✅ Profile imported successfully!
120+
121+
[Belt Emoji] Belt: [belt]
122+
⚡ XP: [xp]
123+
🧠 Concepts mastered: [count]
124+
📊 Quizzes taken: [quizzes.total]
125+
126+
Backup saved to: ~/.code-sensei/profile.json.backup
127+
128+
Your learning progress has been restored.
129+
Use /code-sensei:progress to view your full dashboard.
130+
131+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
132+
🥋 Powered by Dojo Coding | dojocoding.io
133+
```
134+
135+
**If the user cancels:**
136+
137+
```
138+
↩️ Import cancelled. Your current profile was not changed.
139+
```
140+
141+
## Important Notes
142+
143+
- Always back up before overwriting — never skip the backup step
144+
- The preferred import path reads the `profile` field from wrapped exports; legacy/raw exports can be copied directly
145+
- If jq is unavailable, warn the user and provide manual instructions
146+
- After a successful import, do NOT reset session_concepts — preserve it as-is from the imported profile

scripts/export-profile.sh

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#!/bin/bash
2+
# CodeSensei — Export Profile Script
3+
# Exports ~/.code-sensei/profile.json to a timestamped file with metadata wrapper
4+
5+
PROFILE_DIR="$HOME/.code-sensei"
6+
PROFILE_FILE="$PROFILE_DIR/profile.json"
7+
EXPORT_STAMP=$(date -u +%Y-%m-%dT%H-%M-%SZ)
8+
EXPORT_TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
9+
EXPORT_FILE="$HOME/code-sensei-export-${EXPORT_STAMP}-$$.json"
10+
11+
# Resolve plugin version from plugin.json if CLAUDE_PLUGIN_ROOT is set
12+
PLUGIN_VERSION="unknown"
13+
if [ -n "$CLAUDE_PLUGIN_ROOT" ] && [ -f "${CLAUDE_PLUGIN_ROOT}/.claude-plugin/plugin.json" ]; then
14+
if command -v jq &> /dev/null; then
15+
PLUGIN_VERSION=$(jq -r '.version // "unknown"' "${CLAUDE_PLUGIN_ROOT}/.claude-plugin/plugin.json" 2>/dev/null || echo "unknown")
16+
fi
17+
fi
18+
19+
# Check if profile exists
20+
if [ ! -f "$PROFILE_FILE" ]; then
21+
echo "ERROR: No profile found at $PROFILE_FILE" >&2
22+
echo "Run a CodeSensei session first to create your profile." >&2
23+
exit 0
24+
fi
25+
26+
# Export with jq if available (full metadata wrapper)
27+
if command -v jq &> /dev/null; then
28+
jq \
29+
--arg schema_version "1.0" \
30+
--arg exported_at "$EXPORT_TIMESTAMP" \
31+
--arg plugin_version "$PLUGIN_VERSION" \
32+
'{
33+
schema_version: $schema_version,
34+
exported_at: $exported_at,
35+
plugin_version: $plugin_version,
36+
profile: .
37+
}' \
38+
"$PROFILE_FILE" > "$EXPORT_FILE"
39+
40+
if [ $? -ne 0 ]; then
41+
echo "ERROR: Failed to create export file at $EXPORT_FILE" >&2
42+
exit 0
43+
fi
44+
45+
echo "$EXPORT_FILE"
46+
else
47+
# jq not available — still create an importable wrapper without validation/pretty-printing
48+
echo "WARNING: jq not found. Creating export without jq validation/pretty formatting." >&2
49+
echo "Install jq for full export functionality: brew install jq" >&2
50+
51+
{
52+
printf '{\n'
53+
printf ' "schema_version": "1.0",\n'
54+
printf ' "exported_at": "%s",\n' "$EXPORT_TIMESTAMP"
55+
printf ' "plugin_version": "%s",\n' "$PLUGIN_VERSION"
56+
printf ' "profile": '
57+
cat "$PROFILE_FILE"
58+
printf '\n}\n'
59+
} > "$EXPORT_FILE"
60+
61+
if [ $? -ne 0 ]; then
62+
echo "ERROR: Failed to copy profile to $EXPORT_FILE" >&2
63+
exit 0
64+
fi
65+
66+
echo "$EXPORT_FILE"
67+
fi
68+
69+
exit 0

0 commit comments

Comments
 (0)