feat: per-tool settings, persistent settings file, Codex and Antigravity sessions, tokens and hooks (#40 B, C1, C2, D)
Part B: Model Pricing, Hook Configuration and CLAUDE_HOME move from Settings → Dashboard to the Claude Code tab's AgentHub sub-tab (ClaudeAgentHubSettings.tsx); CODEX_HOME is editable in Codex → AgentHub. A home that is or contains the OS home is refused (EBADHOME). Settings persistence: dashboard-saved settings go to ~/.config/agenthub/settings.env (AGENTHUB_SETTINGS_FILE), outside the plugin cache an update wipes. Load order: real env > the checkout's .env > that file. The first CLAUDE_HOME change pins DASHBOARD_DATA_DIR so the DB stays put. C1: codex-usage.js reads Codex rollout journals into sessions (new column tool) and token_usage, tracked per file in codex_rollouts; forks deduped by total vector, sub-agent threads folded into the root; pricing-sync also prices OpenAI models; PricingSettings with a vendor filter. C2: codex-hooks.js installs AgentHub's hooks into $CODEX_HOME/hooks.json on a click, through a stable forwarder; Codex trust is never written. The hook route creates tool='codex' sessions and folds sub-agent hooks into the root. D: antigravity-usage.js reads agy's per-conversation SQLite files (tokens from ModelUsageStats) into tool='antigravity' sessions; antigravity-hooks.js installs the named hook `agenthub` (PreInvocation, PostToolUse, Stop — never PreToolUse) into ~/.gemini/config/hooks.json; Settings → Antigravity tab; Gemini pricing. Whole-change review fixes: sameOriginGuard on both home PUTs, routers.missing on a CLAUDE_HOME change, reset-pricing scope, GET /api/sessions?tool=, clear-data covering the new tables, Codex child-thread events moving no status, hooks owning status only while current, EFOREIGN for a forwarder that is not ours, agy quiet window and turn rules, AGENTHUB_SETTINGS_FILE honoured from .env. Docs, OpenAPI and the CLAUDE.md marker updated. Server 2141, client 779.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"title": "Settings",
|
||||
"subtitle": "Manage pricing, notifications, data, and hooks",
|
||||
"subtitle": "Manage appearance, AI tools, notifications and data",
|
||||
"exportData": "Export Data",
|
||||
"acrossSessions": "Across all tracked sessions",
|
||||
"basedOnUsage": "Based on per-model token usage",
|
||||
@@ -23,8 +23,6 @@
|
||||
"resetResult": "Reset to {{count}} default rules",
|
||||
"addModel": "Add Model",
|
||||
"pattern": "Pattern",
|
||||
"patternPlaceholder": "claude-opus-4%",
|
||||
"namePlaceholder": "Claude Opus 4",
|
||||
"validationRequired": "Pattern and display name are required",
|
||||
"lastUpdated": "Last updated: ",
|
||||
"tooltip": {
|
||||
@@ -36,21 +34,41 @@
|
||||
"manualUpdates": "You must update prices manually",
|
||||
"manualUpdatesBody": "Anthropic publishes pricing changes on their website - there is no live feed. When a new model launches or rates change, edit the matching rule (or add a new one above the catch-all) so newly recorded sessions are costed correctly. Already-stored sessions keep the price that was applied at ingest time.",
|
||||
"apiPricing": "Reference only - API rates",
|
||||
"apiPricingBody": "These are pay-as-you-go API rates. If you use Claude Code on a subscription plan (Pro, Max, Team, or Enterprise), your actual cost is a flat monthly fee, not per-token - so these figures will usually be higher than what you really pay. Treat the costs here as a usage estimate for reference, not a bill."
|
||||
"apiPricingBody": "These are pay-as-you-go API rates. If you use Claude Code on a subscription plan (Pro, Max, Team, or Enterprise), your actual cost is a flat monthly fee, not per-token - so these figures will usually be higher than what you really pay. Treat the costs here as a usage estimate for reference, not a bill.",
|
||||
"synced": "Prices are filled in automatically",
|
||||
"syncedBody": "A model a session uses with no rule of its own is priced from LiteLLM's public price list the first time it is seen. That row is never updated afterwards: edit it here when the vendor's rates change. Already-stored sessions keep the price that was applied at ingest time.",
|
||||
"apiPricingOtherBody": "These are pay-as-you-go API rates. If you use this CLI on a subscription plan, your actual cost is a flat fee, not per-token - so these figures will usually be higher than what you really pay. Treat them as a usage estimate, not a bill."
|
||||
},
|
||||
"cacheWrite5m": "Cache Write (5m)",
|
||||
"cacheWrite1h": "Cache Write (1h)",
|
||||
"fastInput": "Fast Input",
|
||||
"fastOutput": "Fast Output"
|
||||
"fastOutput": "Fast Output",
|
||||
"showAll": "Show all models ({{count}} more)",
|
||||
"empty": {
|
||||
"claude": "No Claude model prices. Reset Defaults restores them.",
|
||||
"openai": "No OpenAI model prices yet. They are added automatically from LiteLLM's price list once a Codex session uses a model, or add one yourself.",
|
||||
"google": "No Gemini model prices yet. They are added automatically from LiteLLM's price list once an Antigravity session uses a model, or add one yourself."
|
||||
},
|
||||
"placeholders": {
|
||||
"claude": {
|
||||
"pattern": "claude-opus-4%",
|
||||
"name": "Claude Opus 4"
|
||||
},
|
||||
"openai": {
|
||||
"pattern": "gpt-5%",
|
||||
"name": "GPT 5"
|
||||
},
|
||||
"google": {
|
||||
"pattern": "gemini-3.8-flash%",
|
||||
"name": "Gemini 3.8 Flash"
|
||||
}
|
||||
}
|
||||
},
|
||||
"claudeHome": {
|
||||
"title": "CLAUDE_HOME",
|
||||
"description": "Root directory for Claude Code session data. Changing this updates the scan path for transcripts and imports immediately.",
|
||||
"save": "Save",
|
||||
"saving": "Saving...",
|
||||
"current": "Current:",
|
||||
"placeholder": "/path/to/claude-home",
|
||||
"saveFailed": "Failed to update CLAUDE_HOME"
|
||||
"routersMissing": "Saved. These lanes name an AI Router profile the new home does not have, and start on Native until it is added there or they are re-pointed: {{lanes}}"
|
||||
},
|
||||
"hooks": {
|
||||
"title": "Hook Configuration",
|
||||
@@ -450,6 +468,7 @@
|
||||
"dashboard": "Dashboard",
|
||||
"claudeCode": "Claude Code",
|
||||
"codex": "Codex",
|
||||
"antigravity": "Antigravity",
|
||||
"aiRouter": "AI Router",
|
||||
"gitCredentials": "Git credentials"
|
||||
},
|
||||
@@ -556,5 +575,54 @@
|
||||
"colSaved": "Saved",
|
||||
"empty": "No git login saved. The git bar asks for one the first time a host needs it.",
|
||||
"badUrl": "Enter the server as a URL, e.g. https://git.example.com"
|
||||
},
|
||||
"homeDir": {
|
||||
"save": "Save",
|
||||
"saving": "Saving...",
|
||||
"current": "Current:",
|
||||
"saveFailed": "Failed to save the directory",
|
||||
"envOwned": "This variable is set by the environment the dashboard started in, or by the checkout's .env — either wins at every start: a value saved here lasts until the next restart."
|
||||
},
|
||||
"codexHome": {
|
||||
"title": "CODEX_HOME",
|
||||
"description": "Root directory for Codex config and session journals. The dashboard reads it, writes AI Router layers into it, and starts every codex lane with it.",
|
||||
"restartNote": "A codex lane already running keeps the home it started with, and shows as idle, until it is restarted.",
|
||||
"placeholder": "/path/to/codex-home",
|
||||
"routersFailed": "Saved, but the AI Router layer could not be re-written for: {{lanes}}"
|
||||
},
|
||||
"codexHooks": {
|
||||
"title": "Codex hooks",
|
||||
"description": "Let Codex report to AgentHub as it works: each tool call in the session's timeline, \"Codex needs your permission\" on the lane card and as a notification, and running/idle the moment a turn starts or ends. Tokens and cost come from Codex's journals either way.",
|
||||
"notInstalled": "Not installed",
|
||||
"untrusted": "Installed — waiting for your trust in Codex",
|
||||
"trusted": "Installed and trusted",
|
||||
"trustNote": "Codex runs a hook only after you trust it. The next time Codex starts it asks you to review new hooks: choose Trust all and continue (or run /hooks). Until then Codex skips them.",
|
||||
"install": "Install",
|
||||
"reinstall": "Reinstall",
|
||||
"refresh": "Refresh",
|
||||
"remove": "Remove",
|
||||
"eventTrusted": "Trusted in Codex",
|
||||
"eventUntrusted": "Not trusted in Codex yet",
|
||||
"eventMissing": "Not installed",
|
||||
"unsupported": "Codex hooks from AgentHub need a POSIX shell, so they are not available on Windows.",
|
||||
"unreadable": "AgentHub cannot read {{path}}: {{error}}",
|
||||
"failed": "Could not change Codex hooks: {{message}}"
|
||||
},
|
||||
"antigravityHooks": {
|
||||
"title": "Antigravity hooks",
|
||||
"description": "Let Antigravity's CLI (agy) report to AgentHub as it works: each tool call in the session's timeline, and running/idle the moment a run starts or ends. Tokens and cost come from agy's conversation files either way.",
|
||||
"notInstalled": "Not installed",
|
||||
"installed": "Installed",
|
||||
"disabled": "Installed but switched off in hooks.json",
|
||||
"note": "agy loads hooks at its next start and asks for no trust. The file is global, so the Antigravity IDE runs the hook too; AgentHub ignores what the IDE sends. agy has no hook for a permission prompt, so an Antigravity lane cannot show \"needs your permission\".",
|
||||
"install": "Install",
|
||||
"reinstall": "Reinstall",
|
||||
"refresh": "Refresh",
|
||||
"remove": "Remove",
|
||||
"eventInstalled": "Installed",
|
||||
"eventMissing": "Not installed",
|
||||
"unsupported": "Antigravity hooks from AgentHub need a POSIX shell, so they are not available on Windows.",
|
||||
"unreadable": "AgentHub cannot read {{path}}: {{error}}",
|
||||
"failed": "Could not change Antigravity hooks: {{message}}"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user