Skip to content

Commit fb7bdf0

Browse files
committed
claude app needs dev mode
1 parent 82eee33 commit fb7bdf0

3 files changed

Lines changed: 76 additions & 32 deletions

File tree

scripts/release.mjs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,14 @@ import { dirname, resolve } from 'path'
77

88
const root = resolve(dirname(fileURLToPath(import.meta.url)), '..')
99

10-
// tauri.conf.json is the version source of truth (used by tauri-apps/tauri-action)
11-
const tauriConfPath = resolve(root, 'src-tauri/tauri.conf.json')
12-
const tauriConf = JSON.parse(readFileSync(tauriConfPath, 'utf8'))
13-
const current = tauriConf.version
10+
// Cargo.toml is the version source of truth (tauri.conf.json inherits it automatically)
11+
const cargoPath = resolve(root, 'src-tauri/Cargo.toml')
12+
const cargo = readFileSync(cargoPath, 'utf8')
13+
const current = cargo.match(/\[package\][^[]*?version\s*=\s*"([^"]*)"/s)?.[1]
14+
if (!current) {
15+
console.error('Could not read version from Cargo.toml. Aborting.')
16+
process.exit(1)
17+
}
1418

1519
const [major, minor, patch] = current.split('.').map(Number)
1620

@@ -55,15 +59,8 @@ rl.question('Bump type (1/2/3 or patch/minor/major): ', (answer) => {
5559
pkg.version = next
5660
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n')
5761

58-
// ── src-tauri/tauri.conf.json ─────────────────────────────────────────────
59-
tauriConf.version = next
60-
writeFileSync(tauriConfPath, JSON.stringify(tauriConf, null, 2) + '\n')
61-
6262
// ── src-tauri/Cargo.toml ──────────────────────────────────────────────────
63-
// Replace `version = "..."` only inside the [package] section
64-
const cargoPath = resolve(root, 'src-tauri/Cargo.toml')
65-
const cargo = readFileSync(cargoPath, 'utf8')
66-
const updatedCargo = cargo.replace(/(\[package\][^\[]*?version\s*=\s*)"[^"]*"/s, `$1"${next}"`)
63+
const updatedCargo = cargo.replace(/(\[package\][^[]*?version\s*=\s*)"[^"]*"/s, `$1"${next}"`)
6764

6865
if (updatedCargo === cargo) {
6966
console.error('Could not locate version field in Cargo.toml. Aborting.')
@@ -74,7 +71,7 @@ rl.question('Bump type (1/2/3 or patch/minor/major): ', (answer) => {
7471

7572
// ── git: commit → tag → push ──────────────────────────────────────────────
7673
try {
77-
execSync('git add package.json src-tauri/tauri.conf.json src-tauri/Cargo.toml', {
74+
execSync('git add package.json src-tauri/Cargo.toml', {
7875
cwd: root,
7976
stdio: 'inherit',
8077
})

src-tauri/src/commands/settings.rs

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -58,25 +58,56 @@ fn find_mcp_binary(app: &AppHandle) -> Option<std::path::PathBuf> {
5858
None
5959
}
6060

61-
#[tauri::command]
62-
pub fn setup_claude_mcp(app: AppHandle) -> Result<(), String> {
63-
let binary = find_mcp_binary(&app).ok_or_else(|| {
64-
"Cannot find timesheeps-mcp binary. Build the project first with `pnpm tauri dev` or `pnpm tauri build`.".to_string()
65-
})?;
61+
/// Returns all candidate Claude Desktop config paths that exist on this machine.
62+
/// Covers both the traditional install (%APPDATA%\Claude) and the Microsoft
63+
/// Store sandboxed install (%LOCALAPPDATA%\Packages\Claude_*\LocalCache\Roaming\Claude).
64+
/// If neither directory exists yet, falls back to the traditional path (creates it).
65+
fn find_claude_config_dirs() -> Vec<std::path::PathBuf> {
66+
let mut dirs: Vec<std::path::PathBuf> = Vec::new();
67+
68+
// Traditional install
69+
if let Ok(appdata) = std::env::var("APPDATA") {
70+
let p = std::path::PathBuf::from(appdata).join("Claude");
71+
if p.exists() {
72+
dirs.push(p);
73+
}
74+
}
6675

67-
let binary_path = binary.to_string_lossy().to_string();
76+
// Store install: %LOCALAPPDATA%\Packages\Claude_<publisher-id>\LocalCache\Roaming\Claude
77+
if let Ok(localappdata) = std::env::var("LOCALAPPDATA") {
78+
let packages = std::path::PathBuf::from(localappdata).join("Packages");
79+
if let Ok(entries) = std::fs::read_dir(&packages) {
80+
for entry in entries.flatten() {
81+
let name = entry.file_name();
82+
let name_str = name.to_string_lossy();
83+
if name_str.starts_with("Claude_") {
84+
let p = entry.path().join("LocalCache").join("Roaming").join("Claude");
85+
if p.exists() {
86+
dirs.push(p);
87+
}
88+
}
89+
}
90+
}
91+
}
6892

69-
// Read existing Claude Desktop config or start fresh
70-
let appdata = std::env::var("APPDATA")
71-
.map_err(|_| "APPDATA environment variable not set".to_string())?;
72-
let claude_dir = std::path::Path::new(&appdata).join("Claude");
73-
std::fs::create_dir_all(&claude_dir)
74-
.map_err(|e| format!("Cannot create Claude config dir: {}", e))?;
93+
// Fallback: create the traditional path if nothing was found
94+
if dirs.is_empty() {
95+
if let Ok(appdata) = std::env::var("APPDATA") {
96+
dirs.push(std::path::PathBuf::from(appdata).join("Claude"));
97+
}
98+
}
99+
100+
dirs
101+
}
75102

76-
let config_path = claude_dir.join("claude_desktop_config.json");
103+
fn write_claude_config(dir: &std::path::Path, binary_path: &str) -> Result<(), String> {
104+
std::fs::create_dir_all(dir)
105+
.map_err(|e| format!("Cannot create {}: {}", dir.display(), e))?;
106+
107+
let config_path = dir.join("claude_desktop_config.json");
77108
let mut config: serde_json::Value = if config_path.exists() {
78109
let content = std::fs::read_to_string(&config_path)
79-
.map_err(|e| format!("Cannot read existing config: {}", e))?;
110+
.map_err(|e| format!("Cannot read {}: {}", config_path.display(), e))?;
80111
serde_json::from_str(&content).unwrap_or(serde_json::json!({}))
81112
} else {
82113
serde_json::json!({})
@@ -85,15 +116,28 @@ pub fn setup_claude_mcp(app: AppHandle) -> Result<(), String> {
85116
if config.get("mcpServers").is_none() {
86117
config["mcpServers"] = serde_json::json!({});
87118
}
88-
89-
config["mcpServers"]["timesheeps"] = serde_json::json!({
90-
"command": binary_path
91-
});
119+
config["mcpServers"]["timesheeps"] = serde_json::json!({ "command": binary_path });
92120

93121
let json = serde_json::to_string_pretty(&config)
94122
.map_err(|e| format!("Cannot serialize config: {}", e))?;
95123
std::fs::write(&config_path, json)
96-
.map_err(|e| format!("Cannot write Claude config: {}", e))?;
124+
.map_err(|e| format!("Cannot write {}: {}", config_path.display(), e))?;
125+
126+
Ok(())
127+
}
128+
129+
#[tauri::command]
130+
pub fn setup_claude_mcp(app: AppHandle) -> Result<(), String> {
131+
let binary = find_mcp_binary(&app).ok_or_else(|| {
132+
"Cannot find timesheeps-mcp binary. Build the project first with `pnpm tauri dev` or `pnpm tauri build`.".to_string()
133+
})?;
134+
135+
let binary_path = binary.to_string_lossy().to_string();
136+
137+
let dirs = find_claude_config_dirs();
138+
for dir in &dirs {
139+
write_claude_config(dir, &binary_path)?;
140+
}
97141

98142
Ok(())
99143
}

src/views/SettingsView.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,9 @@
226226
</span>
227227
<span v-if="claudeStatus === 'error'" class="error-msg">{{ claudeError }}</span>
228228
</div>
229+
<p class="field-hint" style="margin-top: 0.5rem;">
230+
Also enable developer mode in Claude: <strong>Help → Troubleshoot → Enable Developer Mode</strong>
231+
</p>
229232
</section>
230233
</div>
231234

0 commit comments

Comments
 (0)