ude-plugins-official/hookify/205b6e0b3036/skills
2026-03-06T22:50:37.044Z [DEBUG] Checking plugin clangd-lsp: skillsPath=none, skillsPaths=0 paths
2026-03-06T22:50:37.044Z [DEBUG] Checking plugin obsidian: skillsPath=exists, skillsPaths=0 paths
2026-03-06T22:50:37.044Z [DEBUG] Attempting to load skills from plugin obsidian default skillsPath: /home/josie/.claude/plugins/cache/obsidian-skills/obsidian/1.0.0/skills
2026-03-06T22:50:37.044Z [DEBUG] Checking plugin superpowers: skillsPath=exists, skillsPaths=0 paths
2026-03-06T22:50:37.044Z [DEBUG] Attempting to load skills from plugin superpowers default skillsPath: /home/josie/.claude/plugins/cache/superpowers-marketplace/superpowers/4.3.0/skills
2026-03-06T22:50:37.044Z [DEBUG] Plugin loading errors: Plugin k8s not found in marketplace test-marketplace
2026-03-06T22:50:37.044Z [DEBUG] Hooks: checkForNewResponses returning 0 responses
2026-03-06T22:50:37.056Z [DEBUG] Loaded 0 unique skills (0 unconditional, 0 conditional, managed: 0, user: 0, project: 0, additional: 0, legacy commands: 0)
2026-03-06T22:50:37.057Z [DEBUG] MCP server "ide": Tool 'getDiagnostics' completed successfully in 14ms
2026-03-06T22:50:37.064Z [DEBUG] Loaded 3 commands from plugin ralph-loop default directory
2026-03-06T22:50:37.065Z [DEBUG] Loaded 1 commands from plugin code-review default directory
2026-03-06T22:50:37.065Z [DEBUG] Loaded 1 commands from plugin feature-dev default directory
2026-03-06T22:50:37.068Z [DEBUG] Loaded 4 commands from plugin hookify default directory
2026-03-06T22:50:37.068Z [DEBUG] Loaded 3 commands from plugin superpowers default directory
2026-03-06T22:50:37.068Z [DEBUG] Total plugin commands loaded: 12
2026-03-06T22:50:37.069Z [DEBUG] Loaded 1 skills from plugin hookify default directory
2026-03-06T22:50:37.070Z [DEBUG] Loaded 5 skills from plugin obsidian default directory
2026-03-06T22:50:37.072Z [DEBUG] Loaded 14 skills from plugin superpowers default directory
2026-03-06T22:50:37.072Z [DEBUG] Total plugin skills loaded: 20
2026-03-06T22:50:37.073Z [DEBUG] getSkills returning: 0 skill dir commands, 20 plugin skills, 5 bundled skills, 0 builtin plugin skills
2026-03-06T22:50:37.074Z [DEBUG] Sending 32 skills via attachment (initial, 32 total sent)
2026-03-06T22:50:37.074Z [DEBUG] Skill prompt: showing "hookify:writing-rules" (userFacingName="writing-hookify-rules")
2026-03-06T22:50:37.074Z [DEBUG] Skill prompt: showing "obsidian:defuddle" (userFacingName="defuddle")
2026-03-06T22:50:37.074Z [DEBUG] Skill prompt: showing "obsidian:json-canvas" (userFacingName="json-canvas")
2026-03-06T22:50:37.074Z [DEBUG] Skill prompt: showing "obsidian:obsidian-cli" (userFacingName="obsidian-cli")
2026-03-06T22:50:37.074Z [DEBUG] Skill prompt: showing "obsidian:obsidian-bases" (userFacingName="obsidian-bases")
2026-03-06T22:50:37.074Z [DEBUG] Skill prompt: showing "obsidian:obsidian-markdown" (userFacingName="obsidian-markdown")
2026-03-06T22:50:37.074Z [DEBUG] Skill prompt: showing "superpowers:brainstorming" (userFacingName="brainstorming")
2026-03-06T22:50:37.074Z [DEBUG] Skill prompt: showing "superpowers:dispatching-parallel-agents" (userFacingName="dispatching-parallel-agents")
2026-03-06T22:50:37.074Z [DEBUG] Skill prompt: showing "superpowers:executing-plans" (userFacingName="executing-plans")
2026-03-06T22:50:37.074Z [DEBUG] Skill prompt: showing "superpowers:finishing-a-development-branch" (userFacingName="finishing-a-development-branch")
2026-03-06T22:50:37.074Z [DEBUG] Skill prompt: showing "superpowers:receiving-code-review" (userFacingName="receiving-code-review")
2026-03-06T22:50:37.074Z [DEBUG] Skill prompt: showing "superpowers:requesting-code-review" (userFacingName="requesting-code-review")
2026-03-06T22:50:37.074Z [DEBUG] Skill prompt: showing "superpowers:subagent-driven-development" (userFacingName="subagent-driven-development")
2026-03-06T22:50:37.074Z [DEBUG] Skill prompt: showing "superpowers:systematic-debugging" (userFacingName="systematic-debugging")
2026-03-06T22:50:37.074Z [DEBUG] Skill prompt: showing "superpowers:test-driven-development" (userFacingName="test-driven-development")
2026-03-06T22:50:37.074Z [DEBUG] Skill prompt: showing "superpowers:using-git-worktrees" (userFacingName="using-git-worktrees")
2026-03-06T22:50:37.074Z [DEBUG] Skill prompt: showing "superpowers:using-superpowers" (userFacingName="using-superpowers")
2026-03-06T22:50:37.074Z [DEBUG] Skill prompt: showing "superpowers:verification-before-completion" (userFacingName="verification-before-completion")
2026-03-06T22:50:37.074Z [DEBUG] Skill prompt: showing "superpowers:writing-plans" (userFacingName="writing-plans")
2026-03-06T22:50:37.074Z [DEBUG] Skill prompt: showing "superpowers:writing-skills" (userFacingName="writing-skills")
2026-03-06T22:50:37.076Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:50:37.076Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:50:37.076Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:50:37.076Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:50:37.076Z [DEBUG] Getting matching hook commands for UserPromptSubmit with query: undefined
2026-03-06T22:50:37.076Z [DEBUG] Found 1 hook matchers in settings
2026-03-06T22:50:37.076Z [DEBUG] Matched 1 unique hooks for query "no match query" (1 before deduplication)
2026-03-06T22:50:37.119Z [DEBUG] Hooks: Checking initial response for async: {}
2026-03-06T22:50:37.119Z [DEBUG] Hooks: Parsed initial response: {}
2026-03-06T22:50:37.119Z [DEBUG] Hooks: Initial response is not async, continuing normal processing
2026-03-06T22:50:37.124Z [DEBUG] Successfully parsed and validated hook JSON output
2026-03-06T22:50:37.124Z [DEBUG] Hook UserPromptSubmit (UserPromptSubmit) success:
{}
2026-03-06T22:50:37.125Z [DEBUG] FileHistory: Making snapshot for message 915b5035-3d69-4947-8a63-374f057d938c
2026-03-06T22:50:37.125Z [DEBUG] FileHistory: Added snapshot for 915b5035-3d69-4947-8a63-374f057d938c, tracking 0 files
2026-03-06T22:50:37.125Z [DEBUG] MCP server "ide": Calling MCP tool: closeAllDiffTabs
2026-03-06T22:50:37.139Z [DEBUG] MCP server "ide": Tool 'closeAllDiffTabs' completed successfully in 13ms
2026-03-06T22:50:37.140Z [DEBUG] Dynamic tool loading: 0/223 deferred tools included
2026-03-06T22:50:37.141Z [DEBUG] attribution header x-anthropic-billing-header: cc_version=2.1.70.0a4; cc_entrypoint=cli; cch=00000;
2026-03-06T22:50:37.141Z [DEBUG] [API:request] Creating client, ANTHROPIC_CUSTOM_HEADERS present: false, has Authorization header: false
2026-03-06T22:50:37.141Z [DEBUG] [API:auth] OAuth token check starting
2026-03-06T22:50:37.141Z [DEBUG] [API:auth] OAuth token check complete
2026-03-06T22:50:37.143Z [DEBUG] [useDeferredValue] Messages deferred by 4 (6→10)
2026-03-06T22:50:39.223Z [DEBUG] Stream started - received first chunk
2026-03-06T22:50:41.425Z [DEBUG] [useDeferredValue] Messages deferred by 1 (10→11)
2026-03-06T22:50:41.430Z [DEBUG] [useDeferredValue] Messages deferred by 1 (10→11)
2026-03-06T22:50:41.434Z [DEBUG] [useDeferredValue] Messages deferred by 1 (10→11)
2026-03-06T22:50:41.436Z [DEBUG] [useDeferredValue] Messages deferred by 1 (10→11)
2026-03-06T22:50:41.437Z [DEBUG] [useDeferredValue] Messages deferred by 1 (10→11)
2026-03-06T22:50:41.438Z [DEBUG] [useDeferredValue] Messages deferred by 1 (10→11)
2026-03-06T22:50:41.438Z [DEBUG] [useDeferredValue] Messages deferred by 1 (10→11)
2026-03-06T22:50:41.439Z [DEBUG] [useDeferredValue] Messages deferred by 1 (10→11)
2026-03-06T22:50:41.964Z [DEBUG] [useDeferredValue] Messages deferred by 1 (11→12)
2026-03-06T22:50:42.359Z [DEBUG] executePreToolHooks called for tool: ToolSearch
2026-03-06T22:50:42.360Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:50:42.360Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:50:42.360Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:50:42.360Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:50:42.360Z [DEBUG] Getting matching hook commands for PreToolUse with query: ToolSearch
2026-03-06T22:50:42.360Z [DEBUG] Found 1 hook matchers in settings
2026-03-06T22:50:42.360Z [DEBUG] Matched 1 unique hooks for query "ToolSearch" (1 before deduplication)
2026-03-06T22:50:42.361Z [DEBUG] [useDeferredValue] Messages deferred by 1 (12→13)
2026-03-06T22:50:42.374Z [DEBUG] [useDeferredValue] Messages deferred by 1 (13→14)
2026-03-06T22:50:42.376Z [DEBUG] [useDeferredValue] Messages deferred by 1 (13→14)
2026-03-06T22:50:42.408Z [DEBUG] Hooks: Checking initial response for async: {}
2026-03-06T22:50:42.408Z [DEBUG] Hooks: Parsed initial response: {}
2026-03-06T22:50:42.408Z [DEBUG] Hooks: Initial response is not async, continuing normal processing
2026-03-06T22:50:42.430Z [DEBUG] Successfully parsed and validated hook JSON output
2026-03-06T22:50:42.430Z [DEBUG] Hook PreToolUse:ToolSearch (PreToolUse) success:
{}
2026-03-06T22:50:42.431Z [DEBUG] ToolSearchTool: cache invalidated - deferred tools changed
2026-03-06T22:50:42.431Z [DEBUG] ToolSearchTool: selected Read, Glob, Grep
2026-03-06T22:50:42.432Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:50:42.432Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:50:42.432Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:50:42.432Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:50:42.433Z [DEBUG] Getting matching hook commands for PostToolUse with query: ToolSearch
2026-03-06T22:50:42.433Z [DEBUG] Found 6 hook matchers in settings
2026-03-06T22:50:42.433Z [DEBUG] Matched 1 unique hooks for query "ToolSearch" (1 before deduplication)
2026-03-06T22:50:42.462Z [DEBUG] Hooks: Checking initial response for async: {}
2026-03-06T22:50:42.462Z [DEBUG] Hooks: Parsed initial response: {}
2026-03-06T22:50:42.462Z [DEBUG] Hooks: Initial response is not async, continuing normal processing
2026-03-06T22:50:42.471Z [DEBUG] Successfully parsed and validated hook JSON output
2026-03-06T22:50:42.471Z [DEBUG] Hook PostToolUse:ToolSearch (PostToolUse) success:
{}
2026-03-06T22:50:42.478Z [DEBUG] MCP server "ide": Calling MCP tool: getDiagnostics
2026-03-06T22:50:42.478Z [DEBUG] LSP Diagnostics: getLSPDiagnosticAttachments called
2026-03-06T22:50:42.478Z [DEBUG] LSP Diagnostics: Checking registry - 0 pending
2026-03-06T22:50:42.478Z [DEBUG] Hooks: Found 0 total hooks in registry
2026-03-06T22:50:42.478Z [DEBUG] Hooks: checkForNewResponses returning 0 responses
2026-03-06T22:50:42.480Z [DEBUG] [useDeferredValue] Messages deferred by 4 (14→18)
2026-03-06T22:50:42.484Z [DEBUG] MCP server "ide": Tool 'getDiagnostics' completed successfully in 6ms
2026-03-06T22:50:42.484Z [DEBUG] Dynamic tool loading: found 3 discovered tools in message history
2026-03-06T22:50:42.485Z [DEBUG] Dynamic tool loading: 3/223 deferred tools included
2026-03-06T22:50:42.485Z [DEBUG] attribution header x-anthropic-billing-header: cc_version=2.1.70.0a4; cc_entrypoint=cli; cch=00000;
2026-03-06T22:50:42.485Z [DEBUG] [API:request] Creating client, ANTHROPIC_CUSTOM_HEADERS present: false, has Authorization header: false
2026-03-06T22:50:42.485Z [DEBUG] [API:auth] OAuth token check starting
2026-03-06T22:50:42.485Z [DEBUG] [API:auth] OAuth token check complete
2026-03-06T22:50:42.487Z [DEBUG] [useDeferredValue] Messages deferred by 4 (14→18)
2026-03-06T22:50:44.565Z [DEBUG] Stream started - received first chunk
2026-03-06T22:50:45.437Z [DEBUG] executePreToolHooks called for tool: Read
2026-03-06T22:50:45.437Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:50:45.437Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:50:45.437Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:50:45.437Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:50:45.437Z [DEBUG] Getting matching hook commands for PreToolUse with query: Read
2026-03-06T22:50:45.437Z [DEBUG] Found 1 hook matchers in settings
2026-03-06T22:50:45.437Z [DEBUG] Matched 1 unique hooks for query "Read" (1 before deduplication)
2026-03-06T22:50:45.439Z [DEBUG] [useDeferredValue] Messages deferred by 2 (18→20)
2026-03-06T22:50:45.480Z [DEBUG] Hooks: Checking initial response for async: {}
2026-03-06T22:50:45.480Z [DEBUG] Hooks: Parsed initial response: {}
2026-03-06T22:50:45.480Z [DEBUG] Hooks: Initial response is not async, continuing normal processing
2026-03-06T22:50:45.497Z [DEBUG] Successfully parsed and validated hook JSON output
2026-03-06T22:50:45.497Z [DEBUG] Hook PreToolUse:Read (PreToolUse) success:
{}
2026-03-06T22:50:45.499Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:50:45.499Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:50:45.499Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:50:45.499Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:50:45.499Z [DEBUG] Getting matching hook commands for PostToolUse with query: Read
2026-03-06T22:50:45.499Z [DEBUG] Found 6 hook matchers in settings
2026-03-06T22:50:45.499Z [DEBUG] Matched 2 unique hooks for query "Read" (2 before deduplication)
2026-03-06T22:50:45.545Z [DEBUG] Hooks: Checking initial response for async: {}
2026-03-06T22:50:45.545Z [DEBUG] Hooks: Parsed initial response: {}
2026-03-06T22:50:45.545Z [DEBUG] Hooks: Initial response is not async, continuing normal processing
2026-03-06T22:50:45.553Z [DEBUG] Successfully parsed and validated hook JSON output
2026-03-06T22:50:45.554Z [DEBUG] Hook PostToolUse:Read (PostToolUse) success:
{}
2026-03-06T22:50:45.779Z [DEBUG] [useDeferredValue] Messages deferred by 6 (20→26)
2026-03-06T22:50:45.784Z [DEBUG] [useDeferredValue] Messages deferred by 6 (20→26)
2026-03-06T22:50:45.786Z [DEBUG] [useDeferredValue] Messages deferred by 6 (20→26)
2026-03-06T22:50:45.788Z [DEBUG] [useDeferredValue] Messages deferred by 6 (20→26)
2026-03-06T22:50:45.789Z [DEBUG] [useDeferredValue] Messages deferred by 6 (20→26)
2026-03-06T22:50:45.790Z [DEBUG] [useDeferredValue] Messages deferred by 6 (20→26)
2026-03-06T22:50:45.791Z [DEBUG] [useDeferredValue] Messages deferred by 6 (20→26)
2026-03-06T22:50:45.792Z [DEBUG] [useDeferredValue] Messages deferred by 6 (20→26)
2026-03-06T22:50:45.794Z [DEBUG] [useDeferredValue] Messages deferred by 6 (20→26)
2026-03-06T22:50:45.795Z [DEBUG] [useDeferredValue] Messages deferred by 6 (20→26)
2026-03-06T22:50:45.795Z [DEBUG] [useDeferredValue] Messages deferred by 6 (20→26)
2026-03-06T22:50:45.796Z [DEBUG] [useDeferredValue] Messages deferred by 6 (20→26)
2026-03-06T22:50:45.797Z [DEBUG] [useDeferredValue] Messages deferred by 6 (20→26)
2026-03-06T22:50:45.799Z [DEBUG] executePreToolHooks called for tool: Read
2026-03-06T22:50:45.799Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:50:45.799Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:50:45.799Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:50:45.799Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:50:45.799Z [DEBUG] Getting matching hook commands for PreToolUse with query: Read
2026-03-06T22:50:45.799Z [DEBUG] Found 1 hook matchers in settings
2026-03-06T22:50:45.799Z [DEBUG] Matched 1 unique hooks for query "Read" (1 before deduplication)
2026-03-06T22:50:45.801Z [DEBUG] [useDeferredValue] Messages deferred by 7 (20→27)
2026-03-06T22:50:45.818Z [DEBUG] [useDeferredValue] Messages deferred by 1 (27→28)
2026-03-06T22:50:45.821Z [DEBUG] [useDeferredValue] Messages deferred by 1 (27→28)
2026-03-06T22:50:45.848Z [DEBUG] Hooks: Checking initial response for async: {}
2026-03-06T22:50:45.848Z [DEBUG] Hooks: Parsed initial response: {}
2026-03-06T22:50:45.848Z [DEBUG] Hooks: Initial response is not async, continuing normal processing
2026-03-06T22:50:45.865Z [DEBUG] Successfully parsed and validated hook JSON output
2026-03-06T22:50:45.865Z [DEBUG] Hook PreToolUse:Read (PreToolUse) success:
{}
2026-03-06T22:50:45.868Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:50:45.868Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:50:45.868Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:50:45.868Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:50:45.868Z [DEBUG] Getting matching hook commands for PostToolUse with query: Read
2026-03-06T22:50:45.868Z [DEBUG] Found 6 hook matchers in settings
2026-03-06T22:50:45.868Z [DEBUG] Matched 2 unique hooks for query "Read" (2 before deduplication)
2026-03-06T22:50:45.909Z [DEBUG] Hooks: Checking initial response for async: {}
2026-03-06T22:50:45.909Z [DEBUG] Hooks: Parsed initial response: {}
2026-03-06T22:50:45.909Z [DEBUG] Hooks: Initial response is not async, continuing normal processing
2026-03-06T22:50:45.913Z [DEBUG] Successfully parsed and validated hook JSON output
2026-03-06T22:50:45.913Z [DEBUG] Hook PostToolUse:Read (PostToolUse) success:
{}
2026-03-06T22:50:45.914Z [DEBUG] MCP server "ide": Calling MCP tool: getDiagnostics
2026-03-06T22:50:45.914Z [DEBUG] LSP Diagnostics: getLSPDiagnosticAttachments called
2026-03-06T22:50:45.914Z [DEBUG] LSP Diagnostics: Checking registry - 0 pending
2026-03-06T22:50:45.914Z [DEBUG] Hooks: Found 0 total hooks in registry
2026-03-06T22:50:45.915Z [DEBUG] Hooks: checkForNewResponses returning 0 responses
2026-03-06T22:50:45.915Z [DEBUG] MCP server "ide": Tool 'getDiagnostics' completed successfully in 1ms
2026-03-06T22:50:45.916Z [DEBUG] Dynamic tool loading: found 3 discovered tools in message history
2026-03-06T22:50:45.916Z [DEBUG] Dynamic tool loading: 3/223 deferred tools included
2026-03-06T22:50:45.917Z [DEBUG] attribution header x-anthropic-billing-header: cc_version=2.1.70.0a4; cc_entrypoint=cli; cch=00000;
2026-03-06T22:50:45.917Z [DEBUG] [API:request] Creating client, ANTHROPIC_CUSTOM_HEADERS present: false, has Authorization header: false
2026-03-06T22:50:45.917Z [DEBUG] [API:auth] OAuth token check starting
2026-03-06T22:50:45.917Z [DEBUG] [API:auth] OAuth token check complete
2026-03-06T22:50:45.919Z [DEBUG] [useDeferredValue] Messages deferred by 6 (28→34)
2026-03-06T22:50:47.297Z [DEBUG] Stream started - received first chunk
2026-03-06T22:50:48.093Z [DEBUG] [useDeferredValue] Messages deferred by 1 (34→35)
2026-03-06T22:50:48.547Z [DEBUG] [useDeferredValue] Messages deferred by 1 (35→36)
2026-03-06T22:50:48.550Z [DEBUG] [useDeferredValue] Messages deferred by 1 (35→36)
2026-03-06T22:50:48.552Z [DEBUG] [useDeferredValue] Messages deferred by 1 (35→36)
2026-03-06T22:50:49.514Z [DEBUG] executePreToolHooks called for tool: Read
2026-03-06T22:50:49.514Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:50:49.514Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:50:49.515Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:50:49.515Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:50:49.515Z [DEBUG] Getting matching hook commands for PreToolUse with query: Read
2026-03-06T22:50:49.515Z [DEBUG] Found 1 hook matchers in settings
2026-03-06T22:50:49.515Z [DEBUG] Matched 1 unique hooks for query "Read" (1 before deduplication)
2026-03-06T22:50:49.517Z [DEBUG] [useDeferredValue] Messages deferred by 2 (36→38)
2026-03-06T22:50:49.561Z [DEBUG] Hooks: Checking initial response for async: {}
2026-03-06T22:50:49.561Z [DEBUG] Hooks: Parsed initial response: {}
2026-03-06T22:50:49.561Z [DEBUG] Hooks: Initial response is not async, continuing normal processing
2026-03-06T22:50:49.565Z [DEBUG] Successfully parsed and validated hook JSON output
2026-03-06T22:50:49.565Z [DEBUG] Hook PreToolUse:Read (PreToolUse) success:
{}
2026-03-06T22:50:49.567Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:50:49.567Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:50:49.567Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:50:49.567Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:50:49.567Z [DEBUG] Getting matching hook commands for PostToolUse with query: Read
2026-03-06T22:50:49.567Z [DEBUG] Found 6 hook matchers in settings
2026-03-06T22:50:49.567Z [DEBUG] Matched 2 unique hooks for query "Read" (2 before deduplication)
2026-03-06T22:50:49.612Z [DEBUG] Hooks: Checking initial response for async: {}
2026-03-06T22:50:49.612Z [DEBUG] Hooks: Parsed initial response: {}
2026-03-06T22:50:49.612Z [DEBUG] Hooks: Initial response is not async, continuing normal processing
2026-03-06T22:50:49.619Z [DEBUG] Successfully parsed and validated hook JSON output
2026-03-06T22:50:49.619Z [DEBUG] Hook PostToolUse:Read (PostToolUse) success:
{}
2026-03-06T22:50:49.907Z [DEBUG] [useDeferredValue] Messages deferred by 6 (38→44)
2026-03-06T22:50:49.912Z [DEBUG] [useDeferredValue] Messages deferred by 6 (38→44)
2026-03-06T22:50:49.914Z [DEBUG] [useDeferredValue] Messages deferred by 6 (38→44)
2026-03-06T22:50:49.915Z [DEBUG] [useDeferredValue] Messages deferred by 6 (38→44)
2026-03-06T22:50:49.916Z [DEBUG] executePreToolHooks called for tool: Read
2026-03-06T22:50:49.917Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:50:49.917Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:50:49.917Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:50:49.917Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:50:49.917Z [DEBUG] Getting matching hook commands for PreToolUse with query: Read
2026-03-06T22:50:49.917Z [DEBUG] Found 1 hook matchers in settings
2026-03-06T22:50:49.917Z [DEBUG] Matched 1 unique hooks for query "Read" (1 before deduplication)
2026-03-06T22:50:49.918Z [DEBUG] [useDeferredValue] Messages deferred by 8 (38→46)
2026-03-06T22:50:49.961Z [DEBUG] Hooks: Checking initial response for async: {}
2026-03-06T22:50:49.961Z [DEBUG] Hooks: Parsed initial response: {}
2026-03-06T22:50:49.961Z [DEBUG] Hooks: Initial response is not async, continuing normal processing
2026-03-06T22:50:49.966Z [DEBUG] Successfully parsed and validated hook JSON output
2026-03-06T22:50:49.966Z [DEBUG] Hook PreToolUse:Read (PreToolUse) success:
{}
2026-03-06T22:50:49.968Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:50:49.968Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:50:49.968Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:50:49.968Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:50:49.968Z [DEBUG] Getting matching hook commands for PostToolUse with query: Read
2026-03-06T22:50:49.968Z [DEBUG] Found 6 hook matchers in settings
2026-03-06T22:50:49.968Z [DEBUG] Matched 2 unique hooks for query "Read" (2 before deduplication)
2026-03-06T22:50:50.006Z [DEBUG] Hooks: Checking initial response for async: {}
2026-03-06T22:50:50.006Z [DEBUG] Hooks: Parsed initial response: {}
2026-03-06T22:50:50.006Z [DEBUG] Hooks: Initial response is not async, continuing normal processing
2026-03-06T22:50:50.011Z [DEBUG] Successfully parsed and validated hook JSON output
2026-03-06T22:50:50.011Z [DEBUG] Hook PostToolUse:Read (PostToolUse) success:
{}
2026-03-06T22:50:50.012Z [DEBUG] MCP server "ide": Calling MCP tool: getDiagnostics
2026-03-06T22:50:50.012Z [DEBUG] LSP Diagnostics: getLSPDiagnosticAttachments called
2026-03-06T22:50:50.012Z [DEBUG] LSP Diagnostics: Checking registry - 0 pending
2026-03-06T22:50:50.012Z [DEBUG] Hooks: Found 0 total hooks in registry
2026-03-06T22:50:50.013Z [DEBUG] Hooks: checkForNewResponses returning 0 responses
2026-03-06T22:50:50.013Z [DEBUG] MCP server "ide": Tool 'getDiagnostics' completed successfully in 1ms
2026-03-06T22:50:50.014Z [DEBUG] Dynamic tool loading: found 3 discovered tools in message history
2026-03-06T22:50:50.015Z [DEBUG] Dynamic tool loading: 3/223 deferred tools included
2026-03-06T22:50:50.016Z [DEBUG] attribution header x-anthropic-billing-header: cc_version=2.1.70.0a4; cc_entrypoint=cli; cch=00000;
2026-03-06T22:50:50.016Z [DEBUG] [API:request] Creating client, ANTHROPIC_CUSTOM_HEADERS present: false, has Authorization header: false
2026-03-06T22:50:50.016Z [DEBUG] [API:auth] OAuth token check starting
2026-03-06T22:50:50.016Z [DEBUG] [API:auth] OAuth token check complete
2026-03-06T22:50:50.019Z [DEBUG] [useDeferredValue] Messages deferred by 6 (46→52)
2026-03-06T22:50:51.892Z [DEBUG] Stream started - received first chunk
2026-03-06T22:51:13.802Z [DEBUG] [useDeferredValue] Messages deferred by 1 (52→53)
2026-03-06T22:51:13.854Z [DEBUG] [useDeferredValue] Messages deferred by 1 (53→54)
2026-03-06T22:51:13.877Z [DEBUG] [useDeferredValue] Messages deferred by 1 (53→54)
2026-03-06T22:51:13.882Z [DEBUG] [useDeferredValue] Messages deferred by 1 (53→54)
2026-03-06T22:51:15.459Z [DEBUG] [useDeferredValue] Messages deferred by 1 (54→55)
2026-03-06T22:51:15.461Z [DEBUG] executePreToolHooks called for tool: Grep
2026-03-06T22:51:15.461Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:51:15.461Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:51:15.461Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:51:15.461Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:51:15.461Z [DEBUG] Getting matching hook commands for PreToolUse with query: Grep
2026-03-06T22:51:15.461Z [DEBUG] Found 1 hook matchers in settings
2026-03-06T22:51:15.461Z [DEBUG] Matched 1 unique hooks for query "Grep" (1 before deduplication)
2026-03-06T22:51:15.462Z [DEBUG] [useDeferredValue] Messages deferred by 1 (54→55)
2026-03-06T22:51:15.467Z [DEBUG] [useDeferredValue] Messages deferred by 2 (54→56)
2026-03-06T22:51:15.506Z [DEBUG] Hooks: Checking initial response for async: {}
2026-03-06T22:51:15.506Z [DEBUG] Hooks: Parsed initial response: {}
2026-03-06T22:51:15.506Z [DEBUG] Hooks: Initial response is not async, continuing normal processing
2026-03-06T22:51:15.512Z [DEBUG] Successfully parsed and validated hook JSON output
2026-03-06T22:51:15.512Z [DEBUG] Hook PreToolUse:Grep (PreToolUse) success:
{}
2026-03-06T22:51:15.528Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:51:15.528Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:51:15.528Z [DEBUG] detectFileEncoding failed for expected reason: ENOENT
2026-03-06T22:51:15.528Z [DEBUG] Broken symlink or missing file encountered for settings.json at path: /etc/claude-code/managed-settings.json
2026-03-06T22:51:15.529Z [DEBUG] Getting matching hook commands for PostToolUse with query: Grep
2026-03-06T22:51:15.529Z [DEBUG] Found 6 hook matchers in settings
2026-03-06T22:51:15.529Z [DEBUG] Matched 2 unique hooks for query "Grep" (2 before deduplication)
2026-03-06T22:51:15.575Z [DEBUG] Hooks: Checking initial response for async: {}
2use askama::Template;
use askama_web::WebTemplate;
use axum::extract::State;
use axum::http::HeaderMap;
use axum::response::IntoResponse;
use k8s_openapi::api::apps::v1::Deployment;
use k8s_openapi::api::core::v1::Secret;
use kube::{Api, api::ListParams};

use crate::auth_guard::AuthUser;
use crate::flash;
use crate::k8s::SojuBouncer;
use crate::page::PageContext;
use crate::state::AppState;

#[derive(Template, WebTemplate)]
#[template(path = "dashboard.html")]
pub struct DashboardTemplate {
    pub page: PageContext,
    pub has_bouncer: bool,
    pub bouncer_ready: bool,
    pub is_pro: bool,
    pub plan: String,
    pub networks: i64,
    pub channels: i64,
    pub messages_relayed: i64,
    pub bouncer_uptime: String,
    pub paste_count: i64,
    pub paste_storage: String,
    pub pic_count: i64,
    pub pic_storage: String,
}

#[derive(serde::Deserialize)]
struct TxtUsage {
    paste_count: i64,
    storage_bytes: i64,
}

#[derive(serde::Deserialize)]
struct PicsUsage {
    image_count: i64,
    storage_bytes: i64,
}

fn format_bytes(bytes: i64) -> String {
    if bytes < 1024 {
        format!("{bytes} B")
    } else if bytes < 1024 * 1024 {
        format!("{:.1} KB", bytes as f64 / 1024.0)
    } else if bytes < 1024 * 1024 * 1024 {
        format!("{:.1} MB", bytes as f64 / (1024.0 * 1024.0))
    } else {
        format!("{:.1} GB", bytes as f64 / (1024.0 * 1024.0 * 1024.0))
    }
}

fn format_uptime(start: k8s_openapi::jiff::Timestamp) -> String {
    let now = k8s_openapi::jiff::Timestamp::now();
    let dur = now - start;
    let total_hours = dur.get_hours();
    let days = total_hours / 24;
    let hours = total_hours % 24;
    if days > 0 {
        format!("{days}d {hours}h")
    } else {
        format!("{hours}h")
    }
}

pub async fn index(
    State(state): State<AppState>,
    headers: HeaderMap,
    AuthUser(user): AuthUser,
) -> impl IntoResponse {
    let bouncers: Api<SojuBouncer> = Api::namespaced(state.kube.clone(), &state.namespace);
    let lp = ListParams::default().labels(&format!("irc.now/owner={}", user.sub));
    let bouncer_list = bouncers.list(&lp).await.ok();
    let has_bouncer = bouncer_list.as_ref().map(|l| !l.items.is_empty()).unwrap_or(false);
    let bouncer_ready = bouncer_list.as_ref()
        .and_then(|l| l.items.first())
        .and_then(|b| b.status.as_ref())
        .and_then(|s| s.conditions.first())
        .map(|c| c.status == "True")
        .unwrap_or(false);

    let plan = user.plan.unwrap_or_else(|| "free".to_string());
    let is_pro = plan == "pro";

    let (mut networks, mut channels, mut messages_relayed) = (0i64, 0i64, 0i64);
    let mut bouncer_uptime = String::new();

    if let Some(bouncer) = bouncer_list.as_ref().and_then(|l| l.items.first()) {
        let bouncer_name = bouncer.metadata.name.as_deref().unwrap_or_default();

        let deploy_api: Api<Deployment> = Api::namespaced(state.kube.clone(), &state.namespace);
        if let Ok(deploy) = deploy_api.get(bouncer_name).await {
            if let Some(ts) = deploy.metadata.creation_timestamp.as_ref() {
                bouncer_uptime = format_uptime(ts.0);
            }
        }

        if let Ok(stats) = get_bouncer_stats(&state, bouncer_name).await {
            networks = stats.0;
            channels = stats.1;
            messages_relayed = stats.2;
        }
    }

    let txt_usage = async {
        let resp = state.http_client
            .get(format!("{}/api/usage/{}", state.txt_url, user.sub))
            .send().await.ok()?;
        resp.json::<TxtUsage>().await.ok()
    }.await;
    let (paste_count, paste_storage_bytes) = txt_usage
        .map(|u| (u.paste_count, u.storage_bytes))
        .unwrap_or((0, 0));

    let pics_usage = async {
        let resp = state.http_client
            .get(format!("{}/api/usage/{}", state.pics_url, user.sub))
            .send().await.ok()?;
        resp.json::<PicsUsage>().await.ok()
    }.await;
    let (pic_count, pic_storage_bytes) = pics_usage
        .map(|u| (u.image_count, u.storage_bytes))
        .unwrap_or((0, 0));

    let page = PageContext::from_request(&headers, &state.announcement);
    let clear = page.flash.is_some();

    let template = DashboardTemplate {
        page,
        has_bouncer,
        bouncer_ready,
        is_pro,
        plan,
        networks,
        channels,
        messages_relayed,
        bouncer_uptime,
        paste_count,
        paste_storage: format_bytes(paste_storage_bytes),
        pic_count,
        pic_storage: format_bytes(pic_storage_bytes),
    };

    if clear {
        (axum::response::AppendHeaders([flash::clear_flash()]), template).into_response()
    } else {
        template.into_response()
    }
}

async fn get_bouncer_stats(
    state: &AppState,
    bouncer_name: &str,
) -> Result<(i64, i64, i64), Box<dyn std::error::Error>> {
    let secret_api: Api<Secret> = Api::namespaced(state.kube.clone(), &state.namespace);
    let secret = secret_api.get(&format!("{bouncer_name}-db")).await?;

    let uri = secret.data.as_ref()
        .and_then(|d| d.get("uri"))
        .map(|b| String::from_utf8_lossy(&b.0).to_string())
        .ok_or("missing uri in db secret")?;

    let (client, connection) = tokio_postgres::connect(&uri, tokio_postgres::NoTls).await?;
    tokio::spawn(async move {
        if let Err(e) = connection.await {
            tracing::warn!("soju db connection error: {e}");
        }
    });

    let networks: i64 = client
        .query_one(r#"SELECT COUNT(*) FROM "Network""#, &[])
        .await?
        .get(0);

    let channels: i64 = client
        .query_one(r#"SELECT COUNT(*) FROM "Channel""#, &[])
        .await?
        .get(0);

    let messages: i64 = client
        .query_one(r#"SELECT COUNT(*) FROM "MessageTarget""#, &[])
        .await
        .map(|r| r.get(0))
        .unwrap_or(0);

    Ok((networks, channels, messages))
}
