-
Notifications
You must be signed in to change notification settings - Fork 122
feat: global extended context toggle and compact settings UI #63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
35f929a
50c4dcd
1d393bb
fc20cb6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,43 +1,54 @@ | ||||||
| #!/usr/bin/env bash | ||||||
| # Pre-commit hook: auto-rebuild console build artifacts | ||||||
| # Ensures pilot/scripts/*.cjs and pilot/ui/ assets are always in sync with console/src/ | ||||||
|
|
||||||
| set -e | ||||||
|
|
||||||
| # Build artifacts that must stay in sync with console source | ||||||
| ARTIFACTS=( | ||||||
| "pilot/scripts/mcp-server.cjs" | ||||||
| "pilot/scripts/worker-service.cjs" | ||||||
| "pilot/scripts/context-generator.cjs" | ||||||
| "pilot/scripts/worker-wrapper.cjs" | ||||||
| "pilot/ui/viewer-bundle.js" | ||||||
| "pilot/ui/viewer.css" | ||||||
| ) | ||||||
|
|
||||||
| # Check if any console source files are staged | ||||||
| CONSOLE_CHANGED=$(git diff --cached --name-only -- 'console/src/' 'console/scripts/' 'console/package.json' 'console/tsconfig.json' 'console/vite.config.ts' | head -1) | ||||||
|
|
||||||
| if [ -z "$CONSOLE_CHANGED" ]; then | ||||||
| exit 0 | ||||||
| fi | ||||||
| # Pre-commit hook: test gates + auto-rebuild console build artifacts | ||||||
| # | ||||||
| # 1. Python unit tests — when launcher/ or pilot/hooks/ changed | ||||||
| # 2. Console unit tests — when console/ changed | ||||||
| # 3. Console typecheck + build + stage artifacts — when console/src/ changed | ||||||
|
|
||||||
| echo "[pre-commit] Console source changed — rebuilding artifacts..." | ||||||
| set -eo pipefail | ||||||
|
|
||||||
| # Verify node_modules exist | ||||||
| if [ ! -d "console/node_modules" ]; then | ||||||
| echo "[pre-commit] ERROR: console/node_modules missing. Run: cd console && npm install" | ||||||
| exit 1 | ||||||
| fi | ||||||
| # --- 1. Python unit tests --- | ||||||
| PYTHON_CHANGED=$(git diff --cached --name-only -- 'launcher/' 'pilot/hooks/' | head -1) | ||||||
|
|
||||||
| # Rebuild | ||||||
| cd console | ||||||
| if ! npm run build 2>&1 | tail -3; then | ||||||
| echo "[pre-commit] ERROR: Console build failed. Fix build errors before committing." | ||||||
| exit 1 | ||||||
| if [ -n "$PYTHON_CHANGED" ]; then | ||||||
| echo "[pre-commit] Python source changed — running unit tests..." | ||||||
| uv run pytest launcher/tests/ pilot/hooks/tests/ -q --tb=short 2>&1 | tail -5 | ||||||
| echo "[pre-commit] Python unit tests passed." | ||||||
| fi | ||||||
| cd .. | ||||||
|
|
||||||
| # Stage the rebuilt artifacts | ||||||
| git add "${ARTIFACTS[@]}" | ||||||
| # --- 2. Console unit tests --- | ||||||
| CONSOLE_CHANGED=$(git diff --cached --name-only -- 'console/src/' 'console/scripts/' 'console/package.json' 'console/tsconfig.json' 'console/vite.config.ts' | head -1) | ||||||
|
|
||||||
| echo "[pre-commit] Console artifacts rebuilt and staged." | ||||||
| if [ -n "$CONSOLE_CHANGED" ]; then | ||||||
| # Verify node_modules exist | ||||||
| if [ ! -d "console/node_modules" ]; then | ||||||
| echo "[pre-commit] ERROR: console/node_modules missing. Run: cd console && bun install" | ||||||
| exit 1 | ||||||
| fi | ||||||
|
|
||||||
| echo "[pre-commit] Console source changed — running unit tests..." | ||||||
| (cd console && bun test 2>&1) | tail -5 | ||||||
| echo "[pre-commit] Console unit tests passed." | ||||||
|
|
||||||
| # --- 3. Console typecheck + build + stage artifacts --- | ||||||
| echo "[pre-commit] Running typecheck..." | ||||||
| (cd console && bun run typecheck 2>&1) | tail -5 | ||||||
| echo "[pre-commit] Console typecheck passed." | ||||||
|
|
||||||
| echo "[pre-commit] Rebuilding console artifacts..." | ||||||
| (cd console && npm run build 2>&1) | tail -3 | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Lines 30 and 35 use 🛠️ Proposed fix- (cd console && npm run build 2>&1) | tail -3
+ (cd console && bun run build 2>&1) | tail -3📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| echo "" | ||||||
|
|
||||||
| # Build artifacts that must stay in sync with console source | ||||||
| ARTIFACTS=( | ||||||
| "pilot/scripts/mcp-server.cjs" | ||||||
| "pilot/scripts/worker-service.cjs" | ||||||
| "pilot/scripts/context-generator.cjs" | ||||||
| "pilot/scripts/worker-wrapper.cjs" | ||||||
| "pilot/ui/viewer-bundle.js" | ||||||
| "pilot/ui/viewer.css" | ||||||
| ) | ||||||
|
|
||||||
| git add "${ARTIFACTS[@]}" | ||||||
| echo "[pre-commit] Console artifacts rebuilt and staged." | ||||||
| fi | ||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -14,17 +14,18 @@ import * as path from "path"; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { BaseRouteHandler } from "../BaseRouteHandler.js"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { logger } from "../../../../utils/logger.js"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export const MODEL_CHOICES_FULL: readonly string[] = ["sonnet", "sonnet[1m]", "opus", "opus[1m]"]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export const MODEL_CHOICES_AGENT: readonly string[] = ["sonnet", "opus"]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export const MODEL_CHOICES: readonly string[] = ["sonnet", "opus"]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export interface ModelSettings { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| model: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| extendedContext: boolean; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| commands: Record<string, string>; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| agents: Record<string, string>; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export const DEFAULT_SETTINGS: ModelSettings = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| model: "opus", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| extendedContext: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| commands: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| spec: "sonnet", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "spec-plan": "opus", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -47,7 +48,8 @@ export class SettingsRoutes extends BaseRouteHandler { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| constructor(configPath?: string) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| super(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.configPath = configPath ?? path.join(os.homedir(), ".pilot", "config.json"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.configPath = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| configPath ?? path.join(os.homedir(), ".pilot", "config.json"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setupRoutes(app: express.Application): void { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -64,49 +66,98 @@ export class SettingsRoutes extends BaseRouteHandler { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private static stripLegacy1m(model: string): string { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return model.replace("[1m]", ""); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private mergeWithDefaults(raw: Record<string, unknown>): ModelSettings { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const mainModel = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| typeof raw.model === "string" && MODEL_CHOICES_FULL.includes(raw.model) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? raw.model | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let hasLegacy1m = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| typeof raw.model === "string" && raw.model.includes("[1m]"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let mainModel = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| typeof raw.model === "string" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? SettingsRoutes.stripLegacy1m(raw.model) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : DEFAULT_SETTINGS.model; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!MODEL_CHOICES.includes(mainModel)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mainModel = DEFAULT_SETTINGS.model; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const rawCommands = raw.commands; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const mergedCommands: Record<string, string> = { ...DEFAULT_SETTINGS.commands }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (rawCommands && typeof rawCommands === "object" && !Array.isArray(rawCommands)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const [k, v] of Object.entries(rawCommands as Record<string, unknown>)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof v === "string" && MODEL_CHOICES_FULL.includes(v)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mergedCommands[k] = v; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const mergedCommands: Record<string, string> = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...DEFAULT_SETTINGS.commands, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rawCommands && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| typeof rawCommands === "object" && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| !Array.isArray(rawCommands) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const [k, v] of Object.entries( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rawCommands as Record<string, unknown>, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof v === "string") { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (v.includes("[1m]")) hasLegacy1m = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const stripped = SettingsRoutes.stripLegacy1m(v); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (MODEL_CHOICES.includes(stripped)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mergedCommands[k] = stripped; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const rawAgents = raw.agents; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const mergedAgents: Record<string, string> = { ...DEFAULT_SETTINGS.agents }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (rawAgents && typeof rawAgents === "object" && !Array.isArray(rawAgents)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const [k, v] of Object.entries(rawAgents as Record<string, unknown>)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof v === "string" && MODEL_CHOICES_AGENT.includes(v)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mergedAgents[k] = v; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rawAgents && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| typeof rawAgents === "object" && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| !Array.isArray(rawAgents) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const [k, v] of Object.entries( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rawAgents as Record<string, unknown>, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof v === "string") { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const stripped = SettingsRoutes.stripLegacy1m(v); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (MODEL_CHOICES.includes(stripped)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mergedAgents[k] = stripped; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+109
to
124
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agents loop doesn't set The commands loop (lines 94–104) correctly does 🐛 Proposed fix for (const [k, v] of Object.entries(
rawAgents as Record<string, unknown>,
)) {
if (typeof v === "string") {
+ if (v.includes("[1m]")) hasLegacy1m = true;
const stripped = SettingsRoutes.stripLegacy1m(v);
if (MODEL_CHOICES.includes(stripped)) {
mergedAgents[k] = stripped;
}
}
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { model: mainModel, commands: mergedCommands, agents: mergedAgents }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const extendedContext = raw.extendedContext === true || hasLegacy1m; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| model: mainModel, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| extendedContext, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| commands: mergedCommands, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| agents: mergedAgents, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private validateSettings(body: Record<string, unknown>): string | null { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (body.model !== undefined) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof body.model !== "string" || !MODEL_CHOICES_FULL.includes(body.model)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return `Invalid model '${body.model}'; must be one of: ${MODEL_CHOICES_FULL.join(", ")}`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| typeof body.model !== "string" || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| !MODEL_CHOICES.includes(body.model) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return `Invalid model '${body.model}'; must be one of: ${MODEL_CHOICES.join(", ")}`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (body.extendedContext !== undefined) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof body.extendedContext !== "boolean") { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "extendedContext must be a boolean"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (body.commands !== undefined) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof body.commands !== "object" || Array.isArray(body.commands)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "commands must be an object"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const [cmd, model] of Object.entries(body.commands as Record<string, unknown>)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof model !== "string" || !MODEL_CHOICES_FULL.includes(model)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return `Invalid model '${model}' for command '${cmd}'; must be one of: ${MODEL_CHOICES_FULL.join(", ")}`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const [cmd, model] of Object.entries( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| body.commands as Record<string, unknown>, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof model !== "string" || !MODEL_CHOICES.includes(model)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return `Invalid model '${model}' for command '${cmd}'; must be one of: ${MODEL_CHOICES.join(", ")}`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -115,9 +166,11 @@ export class SettingsRoutes extends BaseRouteHandler { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof body.agents !== "object" || Array.isArray(body.agents)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "agents must be an object"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const [agent, model] of Object.entries(body.agents as Record<string, unknown>)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof model !== "string" || !MODEL_CHOICES_AGENT.includes(model)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return `Invalid model '${model}' for agent '${agent}'; agents can only use: ${MODEL_CHOICES_AGENT.join(", ")} (no 1M context)`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const [agent, model] of Object.entries( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| body.agents as Record<string, unknown>, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof model !== "string" || !MODEL_CHOICES.includes(model)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return `Invalid model '${model}' for agent '${agent}'; must be one of: ${MODEL_CHOICES.join(", ")}`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -153,13 +206,23 @@ export class SettingsRoutes extends BaseRouteHandler { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (body.model !== undefined) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| existing.model = body.model; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (body.extendedContext !== undefined) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| existing.extendedContext = body.extendedContext; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (body.commands !== undefined) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const existingCommands = (existing.commands as Record<string, unknown>) ?? {}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| existing.commands = { ...existingCommands, ...(body.commands as Record<string, unknown>) }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const existingCommands = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (existing.commands as Record<string, unknown>) ?? {}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| existing.commands = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...existingCommands, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...(body.commands as Record<string, unknown>), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (body.agents !== undefined) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const existingAgents = (existing.agents as Record<string, unknown>) ?? {}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| existing.agents = { ...existingAgents, ...(body.agents as Record<string, unknown>) }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| existing.agents = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...existingAgents, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...(body.agents as Record<string, unknown>), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
set -eo pipefail+head -1causes spurious hook abort when ≥2 files are stagedWith
pipefailin effect, code likesomecmd | head -n1will sometimes cause an error, depending on whether the output ofsomecmdexceeds the size of the pipe buffer or not. When two or more Python or console files are staged simultaneously,git diffgets SIGPIPE (exit 141) as soon ashead -1closes the pipe. Exit status 141 indicates the program was terminated by SIGPIPE (141 − 128 = 13). When running scripts withset -o pipefail, this terminates the script.Net result: the hook aborts before any tests run whenever a multi-file commit touches
launcher/,pilot/hooks/, orconsole/.The
head -1was likely added as a performance short-circuit, but sincegit diff --cached --name-onlyis fast for a local index check, it's not necessary:🐛 Proposed fix — remove
head -1to eliminate the SIGPIPE entirelygit diff --cached --name-onlyexits 0 in all cases; removinghead -1makesPYTHON_CHANGED/CONSOLE_CHANGEDcapture the full list of changed files (still non-empty ⟹ truthy), with no SIGPIPE risk.Also applies to: 20-20
🤖 Prompt for AI Agents