agent-decoder 0.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agent_decoder-0.3.2/.editorconfig +30 -0
- agent_decoder-0.3.2/.github/CODEOWNERS +7 -0
- agent_decoder-0.3.2/.github/ISSUE_TEMPLATE/bug_report.yml +20 -0
- agent_decoder-0.3.2/.github/ISSUE_TEMPLATE/config.yml +5 -0
- agent_decoder-0.3.2/.github/ISSUE_TEMPLATE/feature_request.yml +13 -0
- agent_decoder-0.3.2/.github/PULL_REQUEST_TEMPLATE.md +44 -0
- agent_decoder-0.3.2/.github/dependabot.yml +31 -0
- agent_decoder-0.3.2/.github/workflows/ci.yml +88 -0
- agent_decoder-0.3.2/.github/workflows/publish.yml +67 -0
- agent_decoder-0.3.2/.gitignore +53 -0
- agent_decoder-0.3.2/.pre-commit-config.yaml +27 -0
- agent_decoder-0.3.2/ARCHITECTURE.md +166 -0
- agent_decoder-0.3.2/CHANGELOG.md +247 -0
- agent_decoder-0.3.2/CODE_OF_CONDUCT.md +83 -0
- agent_decoder-0.3.2/CONTRIBUTING.md +80 -0
- agent_decoder-0.3.2/LICENSE +111 -0
- agent_decoder-0.3.2/Makefile +32 -0
- agent_decoder-0.3.2/PKG-INFO +387 -0
- agent_decoder-0.3.2/README.md +352 -0
- agent_decoder-0.3.2/SECURITY.md +49 -0
- agent_decoder-0.3.2/clau_decode/__init__.py +22 -0
- agent_decoder-0.3.2/docs/demo-poster.jpg +0 -0
- agent_decoder-0.3.2/docs/native-input-required-plan.md +135 -0
- agent_decoder-0.3.2/frontend/index.html +20 -0
- agent_decoder-0.3.2/frontend/package-lock.json +4263 -0
- agent_decoder-0.3.2/frontend/package.json +42 -0
- agent_decoder-0.3.2/frontend/playwright.config.ts +10 -0
- agent_decoder-0.3.2/frontend/public/android-chrome-192x192.png +0 -0
- agent_decoder-0.3.2/frontend/public/android-chrome-512x512.png +0 -0
- agent_decoder-0.3.2/frontend/public/app-icon.png +0 -0
- agent_decoder-0.3.2/frontend/public/apple-touch-icon.png +0 -0
- agent_decoder-0.3.2/frontend/public/favicon-16x16.png +0 -0
- agent_decoder-0.3.2/frontend/public/favicon-32x32.png +0 -0
- agent_decoder-0.3.2/frontend/public/favicon.ico +0 -0
- agent_decoder-0.3.2/frontend/public/site.webmanifest +1 -0
- agent_decoder-0.3.2/frontend/src/App.tsx +356 -0
- agent_decoder-0.3.2/frontend/src/api/__tests__/client.test.ts +265 -0
- agent_decoder-0.3.2/frontend/src/api/client.ts +628 -0
- agent_decoder-0.3.2/frontend/src/api/sessionCache.ts +50 -0
- agent_decoder-0.3.2/frontend/src/api/types.ts +593 -0
- agent_decoder-0.3.2/frontend/src/assets/fonts/LICENSES.md +128 -0
- agent_decoder-0.3.2/frontend/src/assets/fonts/fira-code.woff2 +0 -0
- agent_decoder-0.3.2/frontend/src/assets/fonts/ioskeley-mono.woff2 +0 -0
- agent_decoder-0.3.2/frontend/src/assets/fonts/jetbrains-mono.woff2 +0 -0
- agent_decoder-0.3.2/frontend/src/assets/fonts/julia-mono.woff2 +0 -0
- agent_decoder-0.3.2/frontend/src/assets/fonts/libertinus-mono.woff2 +0 -0
- agent_decoder-0.3.2/frontend/src/assets/fonts/monaspace-argon.woff2 +0 -0
- agent_decoder-0.3.2/frontend/src/assets/fonts/source-code-pro.woff2 +0 -0
- agent_decoder-0.3.2/frontend/src/assets/fonts/spline-sans-mono.woff2 +0 -0
- agent_decoder-0.3.2/frontend/src/assets/fonts/xanh-mono.woff2 +0 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/ChatInput.tsx +497 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/ChatInputBanners.tsx +176 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/ChatInputBar.tsx +91 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/ChatView.tsx +819 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/ConversationHeader.tsx +419 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/EmptyState.tsx +98 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/MessageListContainerContext.ts +5 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/MessageListLoader.tsx +9 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/ModelPicker.tsx +358 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/NativeActionBanner.tsx +111 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/NativeTerminalView.tsx +421 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/OwnershipBanner.tsx +132 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/ProviderThemeContext.tsx +70 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/__tests__/ChatInput.test.tsx +311 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/__tests__/ChatViewLifecycle.test.tsx +579 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/__tests__/ConversationHeader.test.tsx +122 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/__tests__/EmptyState.test.tsx +48 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/__tests__/NativeActionBanner.test.tsx +94 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/__tests__/NativeTerminalView.test.tsx +412 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/chatCard.ts +42 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/hooks/__tests__/useRecaps.test.tsx +88 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/hooks/useExpandPreserveAnchor.ts +48 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/hooks/useMessageHistory.ts +78 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/hooks/useNativePty.ts +158 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/hooks/useRecaps.ts +176 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/hooks/useSessionOwnership.ts +64 -0
- agent_decoder-0.3.2/frontend/src/components/ChatView/nativeTerminal/xtermTerminal.ts +49 -0
- agent_decoder-0.3.2/frontend/src/components/Dashboard/ActivityStrip.tsx +80 -0
- agent_decoder-0.3.2/frontend/src/components/Dashboard/Dashboard.tsx +165 -0
- agent_decoder-0.3.2/frontend/src/components/Dashboard/DashboardEmpty.tsx +57 -0
- agent_decoder-0.3.2/frontend/src/components/Dashboard/DashboardSearch.tsx +288 -0
- agent_decoder-0.3.2/frontend/src/components/Dashboard/FeaturedSession.tsx +168 -0
- agent_decoder-0.3.2/frontend/src/components/Dashboard/HeadlineInsight.tsx +102 -0
- agent_decoder-0.3.2/frontend/src/components/Dashboard/Hero.tsx +34 -0
- agent_decoder-0.3.2/frontend/src/components/Dashboard/ModelRates.tsx +45 -0
- agent_decoder-0.3.2/frontend/src/components/Dashboard/ModelUsageStrip.tsx +47 -0
- agent_decoder-0.3.2/frontend/src/components/Dashboard/ProjectStrip.tsx +89 -0
- agent_decoder-0.3.2/frontend/src/components/Dashboard/SectionHeader.tsx +19 -0
- agent_decoder-0.3.2/frontend/src/components/Dashboard/Sparkline.tsx +40 -0
- agent_decoder-0.3.2/frontend/src/components/Dashboard/StatStrip.tsx +64 -0
- agent_decoder-0.3.2/frontend/src/components/Dashboard/TipCard.tsx +17 -0
- agent_decoder-0.3.2/frontend/src/components/Dashboard/TouchedFilesList.tsx +75 -0
- agent_decoder-0.3.2/frontend/src/components/Dashboard/fmt.ts +46 -0
- agent_decoder-0.3.2/frontend/src/components/ErrorBoundary.tsx +43 -0
- agent_decoder-0.3.2/frontend/src/components/FileViewer/FileViewer.tsx +687 -0
- agent_decoder-0.3.2/frontend/src/components/FileViewer/index.ts +1 -0
- agent_decoder-0.3.2/frontend/src/components/Messages/AssistantMessage.tsx +459 -0
- agent_decoder-0.3.2/frontend/src/components/Messages/ConfirmDialog.tsx +59 -0
- agent_decoder-0.3.2/frontend/src/components/Messages/EphemeralMessage.tsx +144 -0
- agent_decoder-0.3.2/frontend/src/components/Messages/MessageList.tsx +626 -0
- agent_decoder-0.3.2/frontend/src/components/Messages/SidechainBranch.tsx +47 -0
- agent_decoder-0.3.2/frontend/src/components/Messages/StreamingIndicator.tsx +134 -0
- agent_decoder-0.3.2/frontend/src/components/Messages/TextBlock.tsx +244 -0
- agent_decoder-0.3.2/frontend/src/components/Messages/ThinkingBlock.tsx +60 -0
- agent_decoder-0.3.2/frontend/src/components/Messages/ThoughtChain.tsx +790 -0
- agent_decoder-0.3.2/frontend/src/components/Messages/ToolUseBlock.tsx +289 -0
- agent_decoder-0.3.2/frontend/src/components/Messages/UserMessage.tsx +484 -0
- agent_decoder-0.3.2/frontend/src/components/Messages/__tests__/Ephemeral.test.tsx +337 -0
- agent_decoder-0.3.2/frontend/src/components/Messages/__tests__/TextBlock.test.tsx +133 -0
- agent_decoder-0.3.2/frontend/src/components/Messages/__tests__/ToolUseBlock.test.tsx +93 -0
- agent_decoder-0.3.2/frontend/src/components/Messages/__tests__/UserMessage.test.tsx +206 -0
- agent_decoder-0.3.2/frontend/src/components/Messages/blockRenderers.tsx +43 -0
- agent_decoder-0.3.2/frontend/src/components/Messages/groupMessages.ts +116 -0
- agent_decoder-0.3.2/frontend/src/components/Messages/hooks/__tests__/useScrollController.test.tsx +306 -0
- agent_decoder-0.3.2/frontend/src/components/Messages/hooks/__tests__/useSessionDetail.test.ts +245 -0
- agent_decoder-0.3.2/frontend/src/components/Messages/hooks/useCycle.ts +10 -0
- agent_decoder-0.3.2/frontend/src/components/Messages/hooks/useScrollController.ts +309 -0
- agent_decoder-0.3.2/frontend/src/components/Messages/hooks/useSessionDetail.ts +144 -0
- agent_decoder-0.3.2/frontend/src/components/Messages/pairToolBlocks.ts +51 -0
- agent_decoder-0.3.2/frontend/src/components/ScrollContainer.tsx +79 -0
- agent_decoder-0.3.2/frontend/src/components/Settings/NativePtyFontPicker.tsx +107 -0
- agent_decoder-0.3.2/frontend/src/components/Settings/PathEditor.tsx +179 -0
- agent_decoder-0.3.2/frontend/src/components/Settings/PermissionModeSection.tsx +111 -0
- agent_decoder-0.3.2/frontend/src/components/Settings/ProfileSection.tsx +515 -0
- agent_decoder-0.3.2/frontend/src/components/Settings/RecapSettings.tsx +62 -0
- agent_decoder-0.3.2/frontend/src/components/Settings/RescanButton.tsx +39 -0
- agent_decoder-0.3.2/frontend/src/components/Settings/SettingsModal.tsx +527 -0
- agent_decoder-0.3.2/frontend/src/components/Settings/SortOrderSection.tsx +47 -0
- agent_decoder-0.3.2/frontend/src/components/Settings/__tests__/SettingsModal.test.tsx +120 -0
- agent_decoder-0.3.2/frontend/src/components/Settings/shared.tsx +119 -0
- agent_decoder-0.3.2/frontend/src/components/Sidebar/FileExplorer.tsx +368 -0
- agent_decoder-0.3.2/frontend/src/components/Sidebar/HelpPopup.tsx +95 -0
- agent_decoder-0.3.2/frontend/src/components/Sidebar/NewTaskButton.tsx +165 -0
- agent_decoder-0.3.2/frontend/src/components/Sidebar/ProjectGroup.tsx +191 -0
- agent_decoder-0.3.2/frontend/src/components/Sidebar/SearchOverlay.tsx +398 -0
- agent_decoder-0.3.2/frontend/src/components/Sidebar/SessionItem.tsx +596 -0
- agent_decoder-0.3.2/frontend/src/components/Sidebar/ShortcutsPopup.tsx +80 -0
- agent_decoder-0.3.2/frontend/src/components/Sidebar/Sidebar.tsx +1086 -0
- agent_decoder-0.3.2/frontend/src/components/Sidebar/SidebarHeader.tsx +150 -0
- agent_decoder-0.3.2/frontend/src/components/Sidebar/__tests__/NewTaskButton.test.tsx +92 -0
- agent_decoder-0.3.2/frontend/src/components/Sidebar/__tests__/SearchOverlay.test.tsx +39 -0
- agent_decoder-0.3.2/frontend/src/components/Sidebar/__tests__/SessionItem.test.tsx +197 -0
- agent_decoder-0.3.2/frontend/src/components/Sidebar/__tests__/SessionItemRename.test.tsx +149 -0
- agent_decoder-0.3.2/frontend/src/components/Sidebar/hooks/__tests__/useRunnerStatuses.test.tsx +117 -0
- agent_decoder-0.3.2/frontend/src/components/Sidebar/hooks/useRunnerStatuses.ts +127 -0
- agent_decoder-0.3.2/frontend/src/components/Toast.tsx +77 -0
- agent_decoder-0.3.2/frontend/src/components/ui/ContextMenu.tsx +309 -0
- agent_decoder-0.3.2/frontend/src/components/ui/DelayedSkeleton.tsx +36 -0
- agent_decoder-0.3.2/frontend/src/components/ui/LoadingAnimation.tsx +198 -0
- agent_decoder-0.3.2/frontend/src/components/ui/RenameInput.tsx +55 -0
- agent_decoder-0.3.2/frontend/src/components/ui/icons.tsx +75 -0
- agent_decoder-0.3.2/frontend/src/config/ui.ts +45 -0
- agent_decoder-0.3.2/frontend/src/constants/nativePtyFonts.ts +101 -0
- agent_decoder-0.3.2/frontend/src/main.tsx +51 -0
- agent_decoder-0.3.2/frontend/src/router.ts +33 -0
- agent_decoder-0.3.2/frontend/src/store/__tests__/toggleExplorer.test.ts +40 -0
- agent_decoder-0.3.2/frontend/src/store/blocksState.ts +21 -0
- agent_decoder-0.3.2/frontend/src/store/index.ts +183 -0
- agent_decoder-0.3.2/frontend/src/styles/nativePtyFonts.css +73 -0
- agent_decoder-0.3.2/frontend/src/styles/theme.css +733 -0
- agent_decoder-0.3.2/frontend/src/test-setup.ts +1 -0
- agent_decoder-0.3.2/frontend/src/utils/__tests__/lazyWithRetry.test.tsx +96 -0
- agent_decoder-0.3.2/frontend/src/utils/__tests__/sessionMeta.test.tsx +152 -0
- agent_decoder-0.3.2/frontend/src/utils/events.ts +60 -0
- agent_decoder-0.3.2/frontend/src/utils/fileType.ts +40 -0
- agent_decoder-0.3.2/frontend/src/utils/formatRelative.ts +38 -0
- agent_decoder-0.3.2/frontend/src/utils/hljs.ts +88 -0
- agent_decoder-0.3.2/frontend/src/utils/lazyWithRetry.tsx +87 -0
- agent_decoder-0.3.2/frontend/src/utils/localStorage.ts +93 -0
- agent_decoder-0.3.2/frontend/src/utils/nativePtyFocus.ts +15 -0
- agent_decoder-0.3.2/frontend/src/utils/renderSnippet.tsx +12 -0
- agent_decoder-0.3.2/frontend/src/utils/sessionMeta.ts +281 -0
- agent_decoder-0.3.2/frontend/src/utils/timestamps.ts +5 -0
- agent_decoder-0.3.2/frontend/src/utils/useDebounce.ts +10 -0
- agent_decoder-0.3.2/frontend/tests/ghostty-web.pw.ts +70 -0
- agent_decoder-0.3.2/frontend/tsconfig.json +25 -0
- agent_decoder-0.3.2/frontend/tsconfig.node.json +10 -0
- agent_decoder-0.3.2/frontend/vite.config.ts +34 -0
- agent_decoder-0.3.2/pyproject.toml +65 -0
- agent_decoder-0.3.2/scripts/capture-move-bundle.sh +17 -0
- agent_decoder-0.3.2/src/clau_decode/__init__.py +8 -0
- agent_decoder-0.3.2/src/clau_decode/__main__.py +11 -0
- agent_decoder-0.3.2/src/clau_decode/_auth_env.py +118 -0
- agent_decoder-0.3.2/src/clau_decode/_pty_preexec.py +42 -0
- agent_decoder-0.3.2/src/clau_decode/analytics/__init__.py +0 -0
- agent_decoder-0.3.2/src/clau_decode/analytics/aggregator.py +55 -0
- agent_decoder-0.3.2/src/clau_decode/analytics/cost.py +76 -0
- agent_decoder-0.3.2/src/clau_decode/analytics/extractor.py +32 -0
- agent_decoder-0.3.2/src/clau_decode/analytics/fast.py +289 -0
- agent_decoder-0.3.2/src/clau_decode/analytics/models.py +49 -0
- agent_decoder-0.3.2/src/clau_decode/analytics/pricing.py +162 -0
- agent_decoder-0.3.2/src/clau_decode/analytics/prompt.py +34 -0
- agent_decoder-0.3.2/src/clau_decode/analytics/service.py +23 -0
- agent_decoder-0.3.2/src/clau_decode/analytics/stats.py +117 -0
- agent_decoder-0.3.2/src/clau_decode/analytics/tips.py +176 -0
- agent_decoder-0.3.2/src/clau_decode/btw_capture.py +290 -0
- agent_decoder-0.3.2/src/clau_decode/cli.py +504 -0
- agent_decoder-0.3.2/src/clau_decode/config.py +144 -0
- agent_decoder-0.3.2/src/clau_decode/db.py +2054 -0
- agent_decoder-0.3.2/src/clau_decode/driver_manager.py +387 -0
- agent_decoder-0.3.2/src/clau_decode/drivers/__init__.py +27 -0
- agent_decoder-0.3.2/src/clau_decode/drivers/base.py +170 -0
- agent_decoder-0.3.2/src/clau_decode/drivers/registry.py +113 -0
- agent_decoder-0.3.2/src/clau_decode/drivers/tmux_driver.py +488 -0
- agent_decoder-0.3.2/src/clau_decode/editor.py +182 -0
- agent_decoder-0.3.2/src/clau_decode/events_bus.py +69 -0
- agent_decoder-0.3.2/src/clau_decode/locks.py +388 -0
- agent_decoder-0.3.2/src/clau_decode/migrate.py +1313 -0
- agent_decoder-0.3.2/src/clau_decode/models.py +285 -0
- agent_decoder-0.3.2/src/clau_decode/parser.py +466 -0
- agent_decoder-0.3.2/src/clau_decode/providers/__init__.py +30 -0
- agent_decoder-0.3.2/src/clau_decode/providers/base.py +132 -0
- agent_decoder-0.3.2/src/clau_decode/providers/claude.py +81 -0
- agent_decoder-0.3.2/src/clau_decode/providers/codex.py +441 -0
- agent_decoder-0.3.2/src/clau_decode/providers/registry.py +89 -0
- agent_decoder-0.3.2/src/clau_decode/pty_native.py +39 -0
- agent_decoder-0.3.2/src/clau_decode/pty_runner.py +2406 -0
- agent_decoder-0.3.2/src/clau_decode/pty_screen_state.py +65 -0
- agent_decoder-0.3.2/src/clau_decode/recap_runner.py +230 -0
- agent_decoder-0.3.2/src/clau_decode/reporter.py +305 -0
- agent_decoder-0.3.2/src/clau_decode/scanner.py +125 -0
- agent_decoder-0.3.2/src/clau_decode/server.py +2841 -0
- agent_decoder-0.3.2/src/clau_decode/static/android-chrome-192x192.png +0 -0
- agent_decoder-0.3.2/src/clau_decode/static/android-chrome-512x512.png +0 -0
- agent_decoder-0.3.2/src/clau_decode/static/app-icon.png +0 -0
- agent_decoder-0.3.2/src/clau_decode/static/apple-touch-icon.png +0 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/ChatView-BBVXuITs.js +79 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/ChatView-BrP-ENHg.css +1 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/Dashboard-3CYO4HQw.js +1 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/FileViewer-BwbDc3ky.js +1 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/HelpPopup-CPtECjYw.js +1 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/ScrollContainer-BT_Dzxah.js +1 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/SearchOverlay-DqI7aZaC.js +1 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/SessionItem-DlyKg80u.js +1 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/SettingsModal-CZBfMqx7.js +1 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/ShortcutsPopup-W7CPdCzW.js +1 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/Sidebar-BBswhEua.js +1 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/client-DTSXvAb8.js +1 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/fira-code-DGosTW8U.woff2 +0 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/formatRelative-j86webkr.js +1 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/hljs-B3O74O7Z.js +35 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/index-BHdCOIkq.css +10 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/index-DfKltZ6z.js +5 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/ioskeley-mono-C7VR2-sL.woff2 +0 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/jetbrains-mono-V6pRDFza.woff2 +0 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/julia-mono-Cbvba6sW.woff2 +0 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/libertinus-mono-Coz17E-O.woff2 +0 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/monaspace-argon-RS-2TGNg.woff2 +0 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/nativePtyFonts-BaXKtUsn.js +1 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/react-Bi_azaFt.js +9 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/renderSnippet-CqpQQugH.js +1 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/rolldown-runtime-S-ySWqyJ.js +1 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/shared-DdVGprvF.js +1 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/source-code-pro-DEXWLoHG.woff2 +0 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/spline-sans-mono-mUpA6Mve.woff2 +0 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/ui-BcGPjpYn.js +1 -0
- agent_decoder-0.3.2/src/clau_decode/static/assets/xanh-mono-Dsg19vWS.woff2 +0 -0
- agent_decoder-0.3.2/src/clau_decode/static/favicon-16x16.png +0 -0
- agent_decoder-0.3.2/src/clau_decode/static/favicon-32x32.png +0 -0
- agent_decoder-0.3.2/src/clau_decode/static/favicon.ico +0 -0
- agent_decoder-0.3.2/src/clau_decode/static/index.html +24 -0
- agent_decoder-0.3.2/src/clau_decode/static/site.webmanifest +1 -0
- agent_decoder-0.3.2/src/clau_decode/update_check.py +51 -0
- agent_decoder-0.3.2/src/clau_decode/watcher.py +63 -0
- agent_decoder-0.3.2/tests/__init__.py +0 -0
- agent_decoder-0.3.2/tests/analytics/__init__.py +0 -0
- agent_decoder-0.3.2/tests/analytics/test_aggregator.py +161 -0
- agent_decoder-0.3.2/tests/analytics/test_cost.py +112 -0
- agent_decoder-0.3.2/tests/analytics/test_extractor.py +128 -0
- agent_decoder-0.3.2/tests/analytics/test_fast_parity.py +182 -0
- agent_decoder-0.3.2/tests/analytics/test_integration.py +113 -0
- agent_decoder-0.3.2/tests/analytics/test_pricing.py +206 -0
- agent_decoder-0.3.2/tests/analytics/test_prompt.py +78 -0
- agent_decoder-0.3.2/tests/analytics/test_service.py +83 -0
- agent_decoder-0.3.2/tests/analytics/test_stats.py +193 -0
- agent_decoder-0.3.2/tests/analytics/test_tips.py +250 -0
- agent_decoder-0.3.2/tests/conftest.py +9 -0
- agent_decoder-0.3.2/tests/drivers/__init__.py +0 -0
- agent_decoder-0.3.2/tests/drivers/fake_cli.py +67 -0
- agent_decoder-0.3.2/tests/drivers/test_driver_manager.py +412 -0
- agent_decoder-0.3.2/tests/drivers/test_tmux_driver.py +376 -0
- agent_decoder-0.3.2/tests/fixtures/aaaaaaaa-0000-0000-0000-000000000001.jsonl +8 -0
- agent_decoder-0.3.2/tests/fixtures/bad-name.jsonl +1 -0
- agent_decoder-0.3.2/tests/fixtures/bbbbbbbb-0000-0000-0000-000000000002.jsonl +8 -0
- agent_decoder-0.3.2/tests/fixtures/btw_capture/live_zai_no_open_marker.bin +287 -0
- agent_decoder-0.3.2/tests/fixtures/btw_capture/multiline.bin +918 -0
- agent_decoder-0.3.2/tests/fixtures/codex/sample_rollout.jsonl +15 -0
- agent_decoder-0.3.2/tests/fixtures/fake_claude_tui.py +394 -0
- agent_decoder-0.3.2/tests/fixtures/session_with_usage.jsonl +5 -0
- agent_decoder-0.3.2/tests/fixtures/sidechain_session.jsonl +8 -0
- agent_decoder-0.3.2/tests/fixtures/simple_session.jsonl +8 -0
- agent_decoder-0.3.2/tests/providers/__init__.py +0 -0
- agent_decoder-0.3.2/tests/providers/test_claude_adapter.py +179 -0
- agent_decoder-0.3.2/tests/providers/test_codex_adapter.py +413 -0
- agent_decoder-0.3.2/tests/providers/test_registry.py +158 -0
- agent_decoder-0.3.2/tests/test_active_data_sources.py +50 -0
- agent_decoder-0.3.2/tests/test_analytics_ignores_ephemerals.py +276 -0
- agent_decoder-0.3.2/tests/test_auth_env.py +39 -0
- agent_decoder-0.3.2/tests/test_btw_capture.py +405 -0
- agent_decoder-0.3.2/tests/test_cli.py +239 -0
- agent_decoder-0.3.2/tests/test_codex_e2e.py +180 -0
- agent_decoder-0.3.2/tests/test_db.py +883 -0
- agent_decoder-0.3.2/tests/test_db_session_meta.py +117 -0
- agent_decoder-0.3.2/tests/test_delete_sessions.py +268 -0
- agent_decoder-0.3.2/tests/test_dev_import_path.py +32 -0
- agent_decoder-0.3.2/tests/test_e2e.py +864 -0
- agent_decoder-0.3.2/tests/test_editor.py +278 -0
- agent_decoder-0.3.2/tests/test_ephemeral_messages.py +402 -0
- agent_decoder-0.3.2/tests/test_events_bus.py +89 -0
- agent_decoder-0.3.2/tests/test_export_ephemeral.py +375 -0
- agent_decoder-0.3.2/tests/test_locks.py +278 -0
- agent_decoder-0.3.2/tests/test_migrate.py +531 -0
- agent_decoder-0.3.2/tests/test_parser.py +264 -0
- agent_decoder-0.3.2/tests/test_pty_native.py +19 -0
- agent_decoder-0.3.2/tests/test_pty_runner.py +1707 -0
- agent_decoder-0.3.2/tests/test_pty_runner_btw.py +907 -0
- agent_decoder-0.3.2/tests/test_pty_screen_state.py +62 -0
- agent_decoder-0.3.2/tests/test_recaps.py +342 -0
- agent_decoder-0.3.2/tests/test_reporter.py +414 -0
- agent_decoder-0.3.2/tests/test_scanner.py +132 -0
- agent_decoder-0.3.2/tests/test_search_ephemeral.py +274 -0
- agent_decoder-0.3.2/tests/test_server.py +819 -0
- agent_decoder-0.3.2/tests/test_server_capabilities.py +267 -0
- agent_decoder-0.3.2/tests/test_server_open_terminal.py +232 -0
- agent_decoder-0.3.2/tests/test_server_session_title.py +181 -0
- agent_decoder-0.3.2/tests/test_update_check.py +165 -0
- agent_decoder-0.3.2/uv.lock +971 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# EditorConfig — https://editorconfig.org
|
|
2
|
+
# Keeps indentation and line endings consistent across editors.
|
|
3
|
+
# Soft style hint: aim for 80–100 char lines in prose and code where reasonable;
|
|
4
|
+
# no hard max-line-length is enforced here (let ruff/prettier handle that).
|
|
5
|
+
|
|
6
|
+
root = true
|
|
7
|
+
|
|
8
|
+
[*]
|
|
9
|
+
charset = utf-8
|
|
10
|
+
end_of_line = lf
|
|
11
|
+
insert_final_newline = true
|
|
12
|
+
trim_trailing_whitespace = true
|
|
13
|
+
indent_style = space
|
|
14
|
+
indent_size = 2
|
|
15
|
+
|
|
16
|
+
# Python — 4-space indent per PEP 8
|
|
17
|
+
[*.py]
|
|
18
|
+
indent_size = 4
|
|
19
|
+
|
|
20
|
+
# TypeScript / React / styles / JSON / YAML / Markdown — 2-space indent
|
|
21
|
+
[*.{ts,tsx,js,jsx,css,scss,json,yml,yaml,md}]
|
|
22
|
+
indent_size = 2
|
|
23
|
+
|
|
24
|
+
# Markdown often relies on trailing whitespace for hard line breaks
|
|
25
|
+
[*.md]
|
|
26
|
+
trim_trailing_whitespace = false
|
|
27
|
+
|
|
28
|
+
# Makefiles require literal tabs for recipe lines
|
|
29
|
+
[Makefile]
|
|
30
|
+
indent_style = tab
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# CODEOWNERS for Clau-Decode
|
|
2
|
+
#
|
|
3
|
+
# GitHub uses this file to auto-request reviews on pull requests.
|
|
4
|
+
# The last matching pattern for a given file wins, so order matters.
|
|
5
|
+
# Docs: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-security/customizing-your-repository/about-code-owners
|
|
6
|
+
|
|
7
|
+
* @Comradery64
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Report something that's broken or behaving unexpectedly.
|
|
3
|
+
title: "bug: "
|
|
4
|
+
labels: ["bug"]
|
|
5
|
+
body:
|
|
6
|
+
- type: textarea
|
|
7
|
+
id: description
|
|
8
|
+
attributes:
|
|
9
|
+
label: What happened?
|
|
10
|
+
description: Describe the bug. Steps to reproduce, expected behavior, and logs are helpful but optional.
|
|
11
|
+
placeholder: When I click X, the app does Y instead of Z.
|
|
12
|
+
validations:
|
|
13
|
+
required: true
|
|
14
|
+
|
|
15
|
+
- type: textarea
|
|
16
|
+
id: logs
|
|
17
|
+
attributes:
|
|
18
|
+
label: Relevant logs / output
|
|
19
|
+
description: Paste any tracebacks, console output, or errors (optional).
|
|
20
|
+
render: shell
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
blank_issues_enabled: true
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: Questions and general discussion
|
|
4
|
+
url: https://github.com/Comradery64/Clau-Decode/discussions
|
|
5
|
+
about: For usage questions, ideas in flux, or anything that isn't a clear bug or feature request, please use Discussions.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest a new feature, enhancement, or improvement.
|
|
3
|
+
title: "feat: "
|
|
4
|
+
labels: ["enhancement"]
|
|
5
|
+
body:
|
|
6
|
+
- type: textarea
|
|
7
|
+
id: description
|
|
8
|
+
attributes:
|
|
9
|
+
label: What do you want?
|
|
10
|
+
description: Describe the problem or feature. Don't worry about format — just explain what you're looking for.
|
|
11
|
+
placeholder: "It would be great if I could…"
|
|
12
|
+
validations:
|
|
13
|
+
required: true
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Thanks for the PR! Fill out the sections below. Delete any that don't apply.
|
|
3
|
+
Title should follow Conventional Commits (feat:, fix:, chore:, docs:, refactor:, test:, ci:).
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
## Summary
|
|
7
|
+
|
|
8
|
+
<!-- One or two sentences: what does this PR do? -->
|
|
9
|
+
|
|
10
|
+
## Motivation
|
|
11
|
+
|
|
12
|
+
<!-- Why are we making this change? Link the issue this PR closes:
|
|
13
|
+
Closes #123
|
|
14
|
+
-->
|
|
15
|
+
|
|
16
|
+
## Changes
|
|
17
|
+
|
|
18
|
+
<!-- Bullet list of the meaningful changes. Avoid restating the diff line-by-line. -->
|
|
19
|
+
|
|
20
|
+
-
|
|
21
|
+
|
|
22
|
+
## Screenshots
|
|
23
|
+
|
|
24
|
+
<!-- For UI changes, drop before/after screenshots or short clips here.
|
|
25
|
+
Delete this section if not applicable. -->
|
|
26
|
+
|
|
27
|
+
## Testing
|
|
28
|
+
|
|
29
|
+
<!-- What did you run, and what was the result?
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
make test
|
|
33
|
+
cd frontend && npm test
|
|
34
|
+
```
|
|
35
|
+
-->
|
|
36
|
+
|
|
37
|
+
## Checklist
|
|
38
|
+
|
|
39
|
+
- [ ] Tests pass locally (`make test` and `cd frontend && npm test`)
|
|
40
|
+
- [ ] `ruff` is clean (`uv run ruff check .` and `uv run ruff format --check .`)
|
|
41
|
+
- [ ] TypeScript builds (`cd frontend && npm run build`)
|
|
42
|
+
- [ ] `CHANGELOG.md` updated under `[Unreleased]` if user-visible
|
|
43
|
+
- [ ] Docs updated if behavior, CLI flags, or config changed
|
|
44
|
+
- [ ] No telemetry, no remote network calls — data stays on the user's machine
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
# Python dependencies (pyproject.toml at the repo root)
|
|
4
|
+
- package-ecosystem: "pip"
|
|
5
|
+
directory: "/"
|
|
6
|
+
schedule:
|
|
7
|
+
interval: "weekly"
|
|
8
|
+
day: "monday"
|
|
9
|
+
open-pull-requests-limit: 5
|
|
10
|
+
commit-message:
|
|
11
|
+
prefix: "chore"
|
|
12
|
+
|
|
13
|
+
# Frontend dependencies (frontend/package.json)
|
|
14
|
+
- package-ecosystem: "npm"
|
|
15
|
+
directory: "/frontend"
|
|
16
|
+
schedule:
|
|
17
|
+
interval: "weekly"
|
|
18
|
+
day: "monday"
|
|
19
|
+
open-pull-requests-limit: 5
|
|
20
|
+
commit-message:
|
|
21
|
+
prefix: "chore"
|
|
22
|
+
|
|
23
|
+
# GitHub Actions workflow pins
|
|
24
|
+
- package-ecosystem: "github-actions"
|
|
25
|
+
directory: "/"
|
|
26
|
+
schedule:
|
|
27
|
+
interval: "weekly"
|
|
28
|
+
day: "monday"
|
|
29
|
+
open-pull-requests-limit: 5
|
|
30
|
+
commit-message:
|
|
31
|
+
prefix: "chore"
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ci-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
python:
|
|
18
|
+
name: Python (${{ matrix.python-version }})
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
strategy:
|
|
21
|
+
fail-fast: false
|
|
22
|
+
matrix:
|
|
23
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
24
|
+
steps:
|
|
25
|
+
- name: Checkout
|
|
26
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
27
|
+
|
|
28
|
+
- name: Set up uv
|
|
29
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
30
|
+
with:
|
|
31
|
+
python-version: ${{ matrix.python-version }}
|
|
32
|
+
enable-cache: true
|
|
33
|
+
|
|
34
|
+
- name: Install dependencies
|
|
35
|
+
run: uv sync --extra dev
|
|
36
|
+
|
|
37
|
+
- name: Install ruff
|
|
38
|
+
# Pinned (and kept in lockstep with .pre-commit-config.yaml's ruff rev) so
|
|
39
|
+
# CI lint/format results can't drift when a new ruff release changes default
|
|
40
|
+
# rules or formatting. Bump both together intentionally.
|
|
41
|
+
run: uv pip install ruff==0.15.12
|
|
42
|
+
|
|
43
|
+
- name: Lint (ruff check)
|
|
44
|
+
run: uv run ruff check .
|
|
45
|
+
|
|
46
|
+
- name: Format check (ruff format)
|
|
47
|
+
run: uv run ruff format --check .
|
|
48
|
+
|
|
49
|
+
- name: Tests (pytest with coverage)
|
|
50
|
+
# pyproject's [tool.pytest.ini_options] addopts already enables
|
|
51
|
+
# --cov=clau_decode; append an XML report for Codecov upload.
|
|
52
|
+
run: uv run pytest --cov-report=xml
|
|
53
|
+
|
|
54
|
+
- name: Upload coverage to Codecov
|
|
55
|
+
if: matrix.python-version == '3.12'
|
|
56
|
+
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
|
|
57
|
+
with:
|
|
58
|
+
files: ./coverage.xml
|
|
59
|
+
fail_ci_if_error: false
|
|
60
|
+
|
|
61
|
+
frontend:
|
|
62
|
+
name: Frontend
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
defaults:
|
|
65
|
+
run:
|
|
66
|
+
working-directory: frontend
|
|
67
|
+
steps:
|
|
68
|
+
- name: Checkout
|
|
69
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
70
|
+
|
|
71
|
+
- name: Set up Node.js
|
|
72
|
+
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
73
|
+
with:
|
|
74
|
+
node-version: "20"
|
|
75
|
+
cache: npm
|
|
76
|
+
cache-dependency-path: frontend/package-lock.json
|
|
77
|
+
|
|
78
|
+
- name: Install dependencies
|
|
79
|
+
run: npm ci
|
|
80
|
+
|
|
81
|
+
- name: Type-check (tsc --noEmit)
|
|
82
|
+
run: npx tsc --noEmit
|
|
83
|
+
|
|
84
|
+
- name: Build (vite)
|
|
85
|
+
run: npm run build
|
|
86
|
+
|
|
87
|
+
- name: Tests (vitest)
|
|
88
|
+
run: npm test
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: publish-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: false
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
build:
|
|
17
|
+
name: Build distribution
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- name: Checkout
|
|
21
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
22
|
+
|
|
23
|
+
- name: Set up uv
|
|
24
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
25
|
+
with:
|
|
26
|
+
python-version: "3.12"
|
|
27
|
+
|
|
28
|
+
- name: Verify tag matches package version
|
|
29
|
+
# __init__.py is the single source of truth (see its own header
|
|
30
|
+
# comment). A mismatched tag would publish the wrong version to
|
|
31
|
+
# PyPI, where releases are immutable and can only be yanked, not
|
|
32
|
+
# deleted or overwritten.
|
|
33
|
+
run: |
|
|
34
|
+
TAG_VERSION="${GITHUB_REF_NAME#v}"
|
|
35
|
+
PKG_VERSION="$(grep -oP '(?<=^__version__ = ")[^"]+' src/clau_decode/__init__.py)"
|
|
36
|
+
if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
|
|
37
|
+
echo "::error::Tag v$TAG_VERSION does not match __version__ ($PKG_VERSION)"
|
|
38
|
+
exit 1
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
- name: Build sdist and wheel
|
|
42
|
+
run: uv build
|
|
43
|
+
|
|
44
|
+
- name: Upload build artifacts
|
|
45
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
46
|
+
with:
|
|
47
|
+
name: dist
|
|
48
|
+
path: dist/
|
|
49
|
+
|
|
50
|
+
publish:
|
|
51
|
+
name: Publish to PyPI
|
|
52
|
+
needs: build
|
|
53
|
+
runs-on: ubuntu-latest
|
|
54
|
+
environment:
|
|
55
|
+
name: pypi
|
|
56
|
+
url: https://pypi.org/project/agent-decoder/
|
|
57
|
+
permissions:
|
|
58
|
+
id-token: write # required for PyPI trusted publishing (OIDC) — no stored API token
|
|
59
|
+
steps:
|
|
60
|
+
- name: Download build artifacts
|
|
61
|
+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
62
|
+
with:
|
|
63
|
+
name: dist
|
|
64
|
+
path: dist/
|
|
65
|
+
|
|
66
|
+
- name: Publish to PyPI
|
|
67
|
+
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
*.pyo
|
|
5
|
+
*.egg-info/
|
|
6
|
+
dist/
|
|
7
|
+
build/
|
|
8
|
+
.venv/
|
|
9
|
+
.venv*/
|
|
10
|
+
venv/
|
|
11
|
+
.pytest_cache/
|
|
12
|
+
.coverage
|
|
13
|
+
htmlcov/
|
|
14
|
+
|
|
15
|
+
# Databases / scratch
|
|
16
|
+
*.db
|
|
17
|
+
*.tmp
|
|
18
|
+
|
|
19
|
+
# Node
|
|
20
|
+
node_modules/
|
|
21
|
+
frontend/node_modules/
|
|
22
|
+
frontend/dist/
|
|
23
|
+
|
|
24
|
+
# Worktrees
|
|
25
|
+
.worktrees/
|
|
26
|
+
|
|
27
|
+
# OS / editor cruft
|
|
28
|
+
.DS_Store
|
|
29
|
+
Thumbs.db
|
|
30
|
+
*.swp
|
|
31
|
+
*.swo
|
|
32
|
+
.idea/
|
|
33
|
+
.vscode/
|
|
34
|
+
|
|
35
|
+
# Local secrets — never commit
|
|
36
|
+
.env
|
|
37
|
+
.env.*
|
|
38
|
+
!.env.example
|
|
39
|
+
*.pem
|
|
40
|
+
*.key
|
|
41
|
+
secrets.*
|
|
42
|
+
|
|
43
|
+
# Session-edit safety backups (created by --enable-edit before each write)
|
|
44
|
+
*.bak.*.jsonl
|
|
45
|
+
|
|
46
|
+
# Demo fixtures, --demo runtime state, and the VHS recording pipeline are
|
|
47
|
+
# local-only — useful for producing screen recordings but not part of the
|
|
48
|
+
# published source. Keep them on disk, just out of git.
|
|
49
|
+
demo-data/
|
|
50
|
+
demo-reel/
|
|
51
|
+
|
|
52
|
+
# Keep the built static assets — they ship with the package
|
|
53
|
+
!src/clau_decode/static/
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Pre-commit hooks for clau-decode.
|
|
2
|
+
# Install once with `pre-commit install`; run on demand with `pre-commit run --all-files`.
|
|
3
|
+
# pre-commit autoupdate will refresh these revs.
|
|
4
|
+
|
|
5
|
+
repos:
|
|
6
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
7
|
+
rev: v6.0.0
|
|
8
|
+
hooks:
|
|
9
|
+
- id: trailing-whitespace
|
|
10
|
+
- id: end-of-file-fixer
|
|
11
|
+
- id: check-yaml
|
|
12
|
+
- id: check-toml
|
|
13
|
+
- id: check-merge-conflict
|
|
14
|
+
- id: check-added-large-files
|
|
15
|
+
|
|
16
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
17
|
+
rev: v0.15.12
|
|
18
|
+
hooks:
|
|
19
|
+
- id: ruff
|
|
20
|
+
args: [--fix]
|
|
21
|
+
- id: ruff-format
|
|
22
|
+
|
|
23
|
+
- repo: https://github.com/pre-commit/mirrors-prettier
|
|
24
|
+
rev: v4.0.0-alpha.8
|
|
25
|
+
hooks:
|
|
26
|
+
- id: prettier
|
|
27
|
+
files: ^frontend/.*\.(ts|tsx|css|md|json)$
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
This document describes the internal architecture of `clau-decode`. It
|
|
4
|
+
complements [`README.md`](README.md) (user-facing) with the technical detail a
|
|
5
|
+
contributor or reviewer needs to navigate the code.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
Clau-Decode is a single-process, local-first application. A FastAPI server
|
|
10
|
+
(uvicorn, bound to `127.0.0.1:4242` by default) scans your AI coding
|
|
11
|
+
assistant's JSONL session files into a SQLite index, exposes them through a
|
|
12
|
+
JSON HTTP API plus a Server-Sent Events stream, and serves a pre-built React +
|
|
13
|
+
TypeScript SPA from the same origin. A `watchfiles`-based watcher detects
|
|
14
|
+
session-file changes in real time, and a PTY manager drives the local Claude
|
|
15
|
+
CLI in interactive TUI mode through a hidden pseudo-terminal so users can send
|
|
16
|
+
messages from the web UI with subscription-backed interactive behavior.
|
|
17
|
+
Nothing leaves the machine — there is no remote
|
|
18
|
+
backend, no telemetry, and no authentication layer.
|
|
19
|
+
|
|
20
|
+
## Component diagram
|
|
21
|
+
|
|
22
|
+
```mermaid
|
|
23
|
+
flowchart LR
|
|
24
|
+
subgraph Browser
|
|
25
|
+
SPA[React + Vite SPA]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
subgraph LocalMachine[Local machine]
|
|
29
|
+
Server[FastAPI / uvicorn<br/>127.0.0.1:4242]
|
|
30
|
+
DB[(SQLite index<br/>FTS5)]
|
|
31
|
+
Scanner[Scanner + Parser]
|
|
32
|
+
Watcher[watchfiles watcher]
|
|
33
|
+
PtyManager[PTY manager<br/>hidden TUI per chat]
|
|
34
|
+
Recap[Recap runner<br/>PTY fork-session]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
subgraph Filesystem[Filesystem]
|
|
38
|
+
JSONL[~/.claude/projects/**/*.jsonl]
|
|
39
|
+
Cfg[~/.config/clau-decode/config.json]
|
|
40
|
+
Cache[~/.local/share/clau-decode/index.db]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
SPA -->|fetch + EventSource| Server
|
|
44
|
+
Server --> DB
|
|
45
|
+
Server -->|scan + parse on startup| Scanner
|
|
46
|
+
Scanner --> JSONL
|
|
47
|
+
Scanner --> DB
|
|
48
|
+
Watcher -->|fsevents / inotify| JSONL
|
|
49
|
+
Watcher -->|asyncio.Queue| Server
|
|
50
|
+
Server -->|SSE /api/events| SPA
|
|
51
|
+
Server -->|focus/submit| PtyManager
|
|
52
|
+
PtyManager -->|hidden PTY| ClaudeTUI[claude TUI]
|
|
53
|
+
ClaudeTUI -->|appends turns| JSONL
|
|
54
|
+
Server -->|recap on demand| Recap
|
|
55
|
+
Recap -->|spawns claude --fork-session in hidden PTY| JSONL
|
|
56
|
+
Server --> Cfg
|
|
57
|
+
DB --- Cache
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Data flow: opening a session
|
|
61
|
+
|
|
62
|
+
1. User clicks a session in the sidebar.
|
|
63
|
+
2. The frontend router (`frontend/src/router.ts`) updates the URL hash to
|
|
64
|
+
`#/chat/<session_id>` and `App.tsx` reacts to the route change.
|
|
65
|
+
3. `frontend/src/api/client.ts` issues `GET /api/sessions/<session_id>`.
|
|
66
|
+
4. The FastAPI route (`src/clau_decode/server.py`) calls `Database.get_session_detail`
|
|
67
|
+
(`src/clau_decode/db.py`), which reads the session row and its messages
|
|
68
|
+
from SQLite.
|
|
69
|
+
5. If the JSONL file's mtime has changed since the last index update, the
|
|
70
|
+
server re-parses the file via `parse_session` (`src/clau_decode/parser.py`)
|
|
71
|
+
and upserts the new messages back into SQLite before returning.
|
|
72
|
+
6. The route returns a `SessionDetail` JSON document; the React `ChatView`
|
|
73
|
+
component renders markdown, tool-use, thinking, and sidechain blocks.
|
|
74
|
+
7. While the session is open, `/api/events` (SSE) pushes `{"type": "refresh"}`
|
|
75
|
+
payloads whenever the watcher sees the underlying JSONL change. The
|
|
76
|
+
frontend re-fetches and updates in place.
|
|
77
|
+
|
|
78
|
+
## Key directories
|
|
79
|
+
|
|
80
|
+
### Backend — `src/clau_decode/`
|
|
81
|
+
|
|
82
|
+
| Path | Role |
|
|
83
|
+
|------|------|
|
|
84
|
+
| `cli.py` | Argument parsing, subcommands (`dashboard`, `scan`, `today`, `stats`, `tips`), uvicorn launch |
|
|
85
|
+
| `server.py` | FastAPI app: HTTP routes, SSE stream, static SPA mount |
|
|
86
|
+
| `config.py` | XDG-aware config + DB path resolution, atomic config writes |
|
|
87
|
+
| `models.py` | Pydantic models (`AppConfig`, `Project`, `Session`, `Message`, `ContentBlock`, ...) |
|
|
88
|
+
| `scanner.py` | Walks `<root>/projects/*/` for JSONL session files |
|
|
89
|
+
| `parser.py` | Parses JSONL into `Session` + `list[Message]`; builds message trees |
|
|
90
|
+
| `db.py` | Async SQLite layer (`aiosqlite`) with FTS5 for search |
|
|
91
|
+
| `watcher.py` | `watchfiles.awatch` wrapper that emits `WatchEvent`s |
|
|
92
|
+
| `pty_runner.py` | PTY-attached interactive `claude` driver — canonical send path |
|
|
93
|
+
| `recap_runner.py` | Fire-and-forget PTY-on-fork-session driver for inline recaps |
|
|
94
|
+
| `editor.py` | Sandboxed file editing (used by `--enable-edit`) |
|
|
95
|
+
| `reporter.py` | JSON / Markdown export of conversations |
|
|
96
|
+
| `analytics/` | Token + cost engine, daily/weekly aggregators, tool/file/model stats, tip rules |
|
|
97
|
+
| `static/` | Pre-built SPA assets (committed in the wheel; rebuilt by `make frontend`) |
|
|
98
|
+
|
|
99
|
+
### Frontend — `frontend/src/`
|
|
100
|
+
|
|
101
|
+
| Path | Role |
|
|
102
|
+
|------|------|
|
|
103
|
+
| `main.tsx` | React entry point |
|
|
104
|
+
| `App.tsx` | Top-level layout, route-driven view selection, SSE wiring |
|
|
105
|
+
| `router.ts` | Hash-based routing (`/`, `/analytics`, `/chat/<id>`) |
|
|
106
|
+
| `api/` | Typed fetch client; `EventSource` helpers |
|
|
107
|
+
| `store/` | Zustand state stores (selection, UI flags, sidebar) |
|
|
108
|
+
| `components/Sidebar/` | Sidebar, search overlay, help, shortcuts |
|
|
109
|
+
| `components/ChatView/` | Conversation viewer, message blocks, runner panel |
|
|
110
|
+
| `components/Dashboard/` | Home dashboard (hero, heatmap, recap, projects) |
|
|
111
|
+
| `components/Analytics/` | Analytics panel and charts (ECharts) |
|
|
112
|
+
| `components/FileViewer/` | Split-pane file viewer + editor |
|
|
113
|
+
| `components/Settings/` | Settings modal |
|
|
114
|
+
|
|
115
|
+
## Storage
|
|
116
|
+
|
|
117
|
+
Clau-Decode follows the [XDG Base Directory
|
|
118
|
+
spec](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html):
|
|
119
|
+
|
|
120
|
+
| Purpose | Path (default) | Notes |
|
|
121
|
+
|---------|----------------|-------|
|
|
122
|
+
| User config | `~/.config/clau-decode/config.json` (or `$XDG_CONFIG_HOME/clau-decode/config.json`) | Atomic writes (`*.tmp` → rename) |
|
|
123
|
+
| Session index | `~/.local/share/clau-decode/index.db` (or `$XDG_DATA_HOME/clau-decode/index.db`) | SQLite + FTS5; durable (holds stars/archives/titles). Use `--force-refresh` to rescan rather than deleting |
|
|
124
|
+
| Scanned sessions | `~/.claude/projects/**/*.jsonl` (configurable) | Read-only by default; written only via the runner or `--enable-edit` |
|
|
125
|
+
|
|
126
|
+
No remote storage. No outbound network calls except optional pricing-table
|
|
127
|
+
refresh in the analytics module.
|
|
128
|
+
|
|
129
|
+
## Security model
|
|
130
|
+
|
|
131
|
+
- **Bind address.** Defaults to `127.0.0.1`. `--expose` (or `--host 0.0.0.0`)
|
|
132
|
+
binds to all interfaces and prints a warning; intended for trusted networks
|
|
133
|
+
only. There is no authentication.
|
|
134
|
+
- **File viewer.** Reads and (with `--enable-edit`) writes files. Access is
|
|
135
|
+
sandboxed to session-related directories; path traversal and symlink escapes
|
|
136
|
+
are explicitly defended against in `editor.py`. Binary and oversized writes
|
|
137
|
+
are refused. A backup is written next to the original before any edit.
|
|
138
|
+
- **JSONL parsing.** Treated as untrusted input. Malformed lines are skipped
|
|
139
|
+
with a warning; the parser never `eval`s and does not follow URLs.
|
|
140
|
+
- **PTY runner.** Spawns the local CLI binary on the user's behalf, attached
|
|
141
|
+
to a hidden pseudo-terminal. The binary name is derived from the session's
|
|
142
|
+
filesystem layout, not from user-supplied input; `shell=True` is never used.
|
|
143
|
+
`ANTHROPIC_API_KEY` / `ANTHROPIC_AUTH_TOKEN` are stripped from the spawned
|
|
144
|
+
child's env (unless the active profile is API-key authenticated) so a user
|
|
145
|
+
with one of those exported in their shell doesn't accidentally bill against
|
|
146
|
+
the static API key.
|
|
147
|
+
- **No telemetry.** No analytics, no error reporting, no remote logging. The
|
|
148
|
+
CI test suite asserts there are no outbound calls to remote services.
|
|
149
|
+
|
|
150
|
+
See [`SECURITY.md`](SECURITY.md) for the disclosure process and full scope.
|
|
151
|
+
|
|
152
|
+
## Performance notes
|
|
153
|
+
|
|
154
|
+
- **Incremental scan.** Each session row stores the source JSONL's mtime;
|
|
155
|
+
files whose mtime is unchanged are skipped on rescan.
|
|
156
|
+
- **In-memory session-detail cache.** Hot sessions stay in a small LRU on the
|
|
157
|
+
server so repeated fetches don't re-query SQLite.
|
|
158
|
+
- **FTS5 search.** Full-text search uses SQLite's FTS5 virtual table, which
|
|
159
|
+
gives sub-millisecond query times across tens of thousands of messages.
|
|
160
|
+
- **Streaming SSE.** Live updates use a single long-lived `EventSource`
|
|
161
|
+
connection per browser tab; payloads are tiny (`{"type": "refresh"}`).
|
|
162
|
+
- **Lazy frontend chunks.** Heavy components (ChatView, Analytics, Dashboard,
|
|
163
|
+
FileViewer, SearchOverlay, SettingsModal) are `React.lazy`-loaded and
|
|
164
|
+
pre-warmed in the background after first paint.
|
|
165
|
+
- **GZip middleware.** FastAPI compresses JSON responses over a few hundred
|
|
166
|
+
bytes, which keeps session-detail payloads small on large conversations.
|