diff --git a/AGENTS.md b/AGENTS.md index e2974e3..b88ea07 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -54,6 +54,8 @@ Useful env vars from code: ## Important Workflows - Startup binds only to `127.0.0.1`. Reverse proxy/Tailscale exposure is external to this repo. +- Complete development work in `/home/cc-dan/cc/cc-web` first, then sync changes into the sanitized release directory `/home/cc-dan/cc/cc-web_v1.2.7` only after the user confirms the work is ready. +- Treat `/home/cc-dan/cc/cc-web_v1.2.7` as the only publishable tree. Any `git add`, `git commit`, or `git push` for GitHub must be run from that sanitized directory, not from the development directory. - Auth is password-or-token over WebSocket. Failed auth bans non-whitelisted IPs after 3 attempts in 5 minutes. - New messages spawn detached Claude or Codex subprocesses. Output is written to `sessions/-run/output.jsonl` and tailed back to the UI. - `recoverProcesses()` reattaches to still-running detached processes on server restart and finalizes completed runs from leftover run directories. @@ -64,6 +66,7 @@ Useful env vars from code: ## Repo-Specific Safety Constraints - Treat `config/`, `sessions/`, `logs/`, `.env`, and any tokens/passwords as sensitive local state. Do not commit secrets or runtime artifacts. +- The sanitized release directory must not retain private or security-sensitive material such as keys, passwords, tokens, real config values, logs, session data, or other local runtime traces. - Be careful with detached child processes. Avoid deleting `sessions/*-run/`, PID files, or killing agent processes unless the task explicitly requires it. - Prefer facts from code over README. The README is broader and partially out of sync with the checked-out workspace. - When changing WebSocket message types or session JSON shape, verify both `server.js` and `public/app.js`. diff --git a/package.json b/package.json index 06437b8..c95a526 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cc-web", - "version": "1.2.10", + "version": "1.2.11", "private": true, "scripts": { "start": "node server.js", diff --git a/public/app.js b/public/app.js index f7ca124..7875c68 100644 --- a/public/app.js +++ b/public/app.js @@ -33,8 +33,8 @@ const SIDEBAR_SWIPE_MAX_VERTICAL_DRIFT = 42; const MODEL_OPTIONS = [ - { value: 'opus', label: 'Opus', desc: '最强大,适合复杂任务' }, - { value: 'sonnet', label: 'Sonnet', desc: '平衡性能与速度' }, + { value: 'opus', label: 'Opus', desc: '最强大,1M 上下文' }, + { value: 'sonnet', label: 'Sonnet', desc: '平衡性能,1M 上下文' }, { value: 'haiku', label: 'Haiku', desc: '最快速,适合简单任务' }, ]; diff --git a/server.js b/server.js index 13e554d..961dfb8 100644 --- a/server.js +++ b/server.js @@ -510,9 +510,10 @@ const activeProcesses = new Map(); const wsSessionMap = new Map(); // Default fallback MODEL_MAP (overridden by model config at runtime) +// opus/sonnet use [1m] suffix to enable 1M context window by default let MODEL_MAP = { - opus: 'claude-opus-4-6', - sonnet: 'claude-sonnet-4-6', + opus: 'claude-opus-4-6[1m]', + sonnet: 'claude-sonnet-4-6[1m]', haiku: 'claude-haiku-4-5-20251001', }; @@ -670,11 +671,12 @@ function loadClaudeJsonModelMap() { const raw = JSON.parse(fs.readFileSync(p, 'utf8')); const env = raw?.env || {}; const map = {}; - if (env.ANTHROPIC_DEFAULT_OPUS_MODEL) map.opus = env.ANTHROPIC_DEFAULT_OPUS_MODEL; - if (env.ANTHROPIC_DEFAULT_SONNET_MODEL) map.sonnet = env.ANTHROPIC_DEFAULT_SONNET_MODEL; + // Append [1m] to opus/sonnet for 1M context window; haiku uses model name as-is + if (env.ANTHROPIC_DEFAULT_OPUS_MODEL) map.opus = env.ANTHROPIC_DEFAULT_OPUS_MODEL + '[1m]'; + if (env.ANTHROPIC_DEFAULT_SONNET_MODEL) map.sonnet = env.ANTHROPIC_DEFAULT_SONNET_MODEL + '[1m]'; if (env.ANTHROPIC_DEFAULT_HAIKU_MODEL) map.haiku = env.ANTHROPIC_DEFAULT_HAIKU_MODEL; // Fallback: ANTHROPIC_MODEL maps to opus slot - if (!map.opus && env.ANTHROPIC_MODEL) map.opus = env.ANTHROPIC_MODEL; + if (!map.opus && env.ANTHROPIC_MODEL) map.opus = env.ANTHROPIC_MODEL + '[1m]'; return Object.keys(map).length > 0 ? map : null; } catch { return null; @@ -716,8 +718,8 @@ function applyModelConfig() { if (config.mode === 'custom' && config.activeTemplate) { const tpl = (config.templates || []).find(t => t.name === config.activeTemplate); if (tpl) { - if (tpl.opusModel) MODEL_MAP.opus = tpl.opusModel; - if (tpl.sonnetModel) MODEL_MAP.sonnet = tpl.sonnetModel; + if (tpl.opusModel) MODEL_MAP.opus = tpl.opusModel.endsWith('[1m]') ? tpl.opusModel : tpl.opusModel + '[1m]'; + if (tpl.sonnetModel) MODEL_MAP.sonnet = tpl.sonnetModel.endsWith('[1m]') ? tpl.sonnetModel : tpl.sonnetModel + '[1m]'; if (tpl.haikuModel) MODEL_MAP.haiku = tpl.haikuModel; return; } @@ -2182,7 +2184,8 @@ function handleNewSession(ws, msg) { claudeSessionId: null, codexThreadId: null, // For Codex: explicitly set a default model on creation so we don't inherit Codex CLI defaults. - model: agent === 'codex' ? DEFAULT_CODEX_MODEL : null, + // For Claude: default to opus (1M) so --model is always passed to CLI. + model: agent === 'codex' ? DEFAULT_CODEX_MODEL : MODEL_MAP.opus, permissionMode: requestedMode, totalCost: 0, totalUsage: { inputTokens: 0, cachedInputTokens: 0, outputTokens: 0 },