diff --git a/ai-memory/feature-server-only-file-watching-55c4316/init.md b/ai-memory/feature-server-only-file-watching-55c4316/init.md new file mode 100644 index 00000000..bb669d53 --- /dev/null +++ b/ai-memory/feature-server-only-file-watching-55c4316/init.md @@ -0,0 +1,10 @@ +# Feature: Server-Only File Watching Setting + +## User Request +Add a new user setting `serverOnlyFileWatching` (boolean, default: false) that controls whether nodemon watches only server files, so client-only changes via git pull don't restart the server. + +## Requirements +1. New user setting in `user-settings.json` and defaults +2. Launcher script `scripts/dev-server.js` that reads the setting and spawns nodemon accordingly +3. Settings UI toggle in the client settings panel +4. Follows existing patterns for server-persisted settings diff --git a/ai-memory/feature-server-only-file-watching-55c4316/plan.md b/ai-memory/feature-server-only-file-watching-55c4316/plan.md new file mode 100644 index 00000000..32168afd --- /dev/null +++ b/ai-memory/feature-server-only-file-watching-55c4316/plan.md @@ -0,0 +1,17 @@ +# Implementation Plan + +## Files to modify +1. `server/userSettingsService.js` - Add `serverOnlyFileWatching` to `getDefaultSettings()` under `global` +2. `user-settings.default.json` - Add the default setting +3. `scripts/dev-server.js` - New launcher script (reads setting, spawns nodemon) +4. `package.json` - Point `dev:server` at the launcher +5. `client/index.html` - Add toggle to settings panel +6. `client/app.js` - Add event listener + sync for the toggle + +## Implementation order +1. Add setting to defaults (server + default JSON) +2. Create launcher script +3. Update package.json +4. Add UI toggle +5. Syntax check + test +6. Commit, push, PR diff --git a/ai-memory/feature-server-only-file-watching-55c4316/progress.md b/ai-memory/feature-server-only-file-watching-55c4316/progress.md new file mode 100644 index 00000000..d54e0a57 --- /dev/null +++ b/ai-memory/feature-server-only-file-watching-55c4316/progress.md @@ -0,0 +1,10 @@ +# Progress + +- [x] Add setting to server defaults +- [x] Add setting to user-settings.default.json +- [x] Create scripts/dev-server.js launcher +- [x] Update package.json dev:server script +- [x] Add UI toggle in settings panel +- [x] Add event listener + sync in app.js +- [x] Syntax check +- [ ] Commit, push, PR diff --git a/client/app.js b/client/app.js index 85d3639b..90a3be7c 100644 --- a/client/app.js +++ b/client/app.js @@ -2444,6 +2444,14 @@ class ClaudeOrchestrator { }); } + // Server-only file watching (server-persisted, requires dev:server restart) + const serverOnlyFileWatching = document.getElementById('server-only-file-watching'); + if (serverOnlyFileWatching) { + serverOnlyFileWatching.addEventListener('change', async (e) => { + await this.updateGlobalUserSetting('serverOnlyFileWatching', !!e.target.checked); + }); + } + // Discord services auto-start (server-persisted) const discordAutoEnsure = document.getElementById('discord-auto-ensure-services'); if (discordAutoEnsure) { @@ -14995,6 +15003,11 @@ class ClaudeOrchestrator { } this.applySimpleModeConfig(); + const serverOnlyFileWatching = document.getElementById('server-only-file-watching'); + if (serverOnlyFileWatching) { + serverOnlyFileWatching.checked = this.userSettings.global?.serverOnlyFileWatching === true; + } + const discordAutoEnsure = document.getElementById('discord-auto-ensure-services'); if (discordAutoEnsure) { const cfg = this.userSettings.global?.ui?.discord || {}; diff --git a/client/index.html b/client/index.html index ba088462..ddf95886 100644 --- a/client/index.html +++ b/client/index.html @@ -536,6 +536,17 @@

Projects + Chats

+
+

Developer

+
+ +

Only restart server when server files change. Client changes take effect on browser refresh.

+
+
+

Glossary

A quick mental model for how the Orchestrator is structured.

diff --git a/package.json b/package.json index d491bcea..ab4ed6b7 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "server/index.js", "scripts": { "start": "npm run dev", - "dev:server": "node scripts/ensure-pty.js && nodemon server/index.js", + "dev:server": "node scripts/ensure-pty.js && node scripts/dev-server.js", "dev:client": "node client/dev-server.js", "dev:diff": "cd diff-viewer && npm run dev", "tauri": "tauri", diff --git a/scripts/dev-server.js b/scripts/dev-server.js new file mode 100644 index 00000000..22ca03b5 --- /dev/null +++ b/scripts/dev-server.js @@ -0,0 +1,48 @@ +#!/usr/bin/env node + +const { spawn } = require('child_process'); +const fs = require('fs'); +const path = require('path'); + +const projectRoot = path.resolve(__dirname, '..'); + +function loadServerOnlyFileWatching() { + const settingsPath = process.env.ORCHESTRATOR_USER_SETTINGS_PATH + || path.join(projectRoot, 'user-settings.json'); + + try { + if (fs.existsSync(settingsPath)) { + const data = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); + return data?.global?.serverOnlyFileWatching === true; + } + } catch { + // Fall through to default + } + return false; +} + +const serverOnly = loadServerOnlyFileWatching(); + +const nodemonBin = path.join(projectRoot, 'node_modules', '.bin', 'nodemon'); +const args = []; + +if (serverOnly) { + // Explicit watch list overrides nodemon.json watch config + args.push('--watch', 'server/', '--watch', '.env'); +} + +args.push('server/index.js'); + +if (process.argv.includes('--dry-run')) { + console.log('serverOnlyFileWatching:', serverOnly); + console.log('command:', nodemonBin, args.join(' ')); + process.exit(0); +} + +const child = spawn(nodemonBin, args, { + cwd: projectRoot, + stdio: 'inherit', + env: process.env +}); + +child.on('exit', (code) => process.exit(code ?? 1)); diff --git a/server/userSettingsService.js b/server/userSettingsService.js index 1bf9c88f..52012126 100644 --- a/server/userSettingsService.js +++ b/server/userSettingsService.js @@ -54,6 +54,7 @@ class UserSettingsService { terminal: { // Add other global terminal settings here in the future }, + serverOnlyFileWatching: false, process: { status: { lookbackHours: 24, @@ -595,6 +596,9 @@ class UserSettingsService { if (userSettings.global.terminal) { Object.assign(merged.global.terminal, userSettings.global.terminal); } + if (typeof userSettings.global.serverOnlyFileWatching === 'boolean') { + merged.global.serverOnlyFileWatching = userSettings.global.serverOnlyFileWatching; + } if (userSettings.global.process) { const procDefaults = (merged.global.process || {}); const proc = userSettings.global.process || {}; diff --git a/user-settings.default.json b/user-settings.default.json index f0f98b00..90065432 100644 --- a/user-settings.default.json +++ b/user-settings.default.json @@ -11,6 +11,7 @@ "delay": 500 }, "terminal": {}, + "serverOnlyFileWatching": false, "scheduler": { "enabled": false, "tickSeconds": 30,