painapple-code 1.0.0__py3-none-any.whl
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.
- painapple_code/__init__.py +30 -0
- painapple_code/__main__.py +18 -0
- painapple_code/_version.py +24 -0
- painapple_code/auth_middleware.py +930 -0
- painapple_code/cli/__init__.py +204 -0
- painapple_code/cli/deploy/__init__.py +15 -0
- painapple_code/cli/deploy/claude_seed.py +41 -0
- painapple_code/cli/deploy/config.py +260 -0
- painapple_code/cli/deploy/container.py +715 -0
- painapple_code/cli/deploy/launch.py +163 -0
- painapple_code/cli/deploy/runtime.py +223 -0
- painapple_code/cli/lifecycle_cmd.py +443 -0
- painapple_code/cli/list_cmd.py +572 -0
- painapple_code/cli/manage_cmd.py +670 -0
- painapple_code/cli/netinfo.py +125 -0
- painapple_code/cli/profiles.py +390 -0
- painapple_code/cli/serve_args.py +163 -0
- painapple_code/cli/serve_config.py +256 -0
- painapple_code/cli/setup_cmd.py +664 -0
- painapple_code/cli/ui.py +438 -0
- painapple_code/cost_analytics.py +879 -0
- painapple_code/data/models.defaults.yaml +18 -0
- painapple_code/data/models.yaml +18 -0
- painapple_code/data/presets.defaults.json +32 -0
- painapple_code/data/strings.yaml +2269 -0
- painapple_code/helpers.py +406 -0
- painapple_code/paths.py +1514 -0
- painapple_code/prompt_explorer.py +984 -0
- painapple_code/providers/__init__.py +224 -0
- painapple_code/providers/base.py +710 -0
- painapple_code/providers/claude/__init__.py +74 -0
- painapple_code/providers/claude/capabilities.py +218 -0
- painapple_code/providers/claude/errors.py +79 -0
- painapple_code/providers/claude/launch.py +50 -0
- painapple_code/providers/claude/summary.py +89 -0
- painapple_code/providers/claude/translate.py +74 -0
- painapple_code/providers/claude_sdk/__init__.py +139 -0
- painapple_code/providers/claude_sdk/driver.py +412 -0
- painapple_code/providers/codex/__init__.py +87 -0
- painapple_code/providers/codex/capabilities.py +321 -0
- painapple_code/providers/codex/errors.py +70 -0
- painapple_code/providers/codex/launch.py +142 -0
- painapple_code/providers/codex/summary.py +196 -0
- painapple_code/providers/codex/translate.py +204 -0
- painapple_code/providers/codex_app_server/__init__.py +100 -0
- painapple_code/providers/codex_app_server/capabilities.py +41 -0
- painapple_code/providers/codex_app_server/launch.py +202 -0
- painapple_code/providers/codex_app_server/summary.py +291 -0
- painapple_code/providers/codex_app_server/translate.py +263 -0
- painapple_code/providers/codex_app_server/transport.py +238 -0
- painapple_code/routes/__init__.py +0 -0
- painapple_code/routes/api_agents.py +441 -0
- painapple_code/routes/api_app.py +368 -0
- painapple_code/routes/api_app_commit_sections.py +127 -0
- painapple_code/routes/api_app_config.py +997 -0
- painapple_code/routes/api_app_session_prefs.py +217 -0
- painapple_code/routes/api_browser.py +690 -0
- painapple_code/routes/api_commands.py +374 -0
- painapple_code/routes/api_costs.py +128 -0
- painapple_code/routes/api_drafts.py +139 -0
- painapple_code/routes/api_exec.py +149 -0
- painapple_code/routes/api_files.py +542 -0
- painapple_code/routes/api_git.py +657 -0
- painapple_code/routes/api_logs.py +649 -0
- painapple_code/routes/api_plugins.py +275 -0
- painapple_code/routes/api_project_config.py +418 -0
- painapple_code/routes/api_prompts.py +231 -0
- painapple_code/routes/api_providers.py +53 -0
- painapple_code/routes/api_search.py +411 -0
- painapple_code/routes/api_session_stash.py +234 -0
- painapple_code/routes/api_session_welcome.py +151 -0
- painapple_code/routes/api_sessions.py +742 -0
- painapple_code/routes/api_shadow.py +323 -0
- painapple_code/routes/api_shadow_db.py +512 -0
- painapple_code/routes/api_shadow_files.py +332 -0
- painapple_code/routes/api_shadow_search.py +476 -0
- painapple_code/routes/api_skills.py +610 -0
- painapple_code/routes/api_tasks.py +147 -0
- painapple_code/routes/api_terminal.py +540 -0
- painapple_code/routes/api_upload.py +293 -0
- painapple_code/routes/api_viewer.py +229 -0
- painapple_code/routes/dependencies.py +109 -0
- painapple_code/routes/ws_chat.py +837 -0
- painapple_code/server.py +2208 -0
- painapple_code/server_logging.py +263 -0
- painapple_code/services/__init__.py +0 -0
- painapple_code/services/agent_session.py +2738 -0
- painapple_code/session_store.py +253 -0
- painapple_code/session_store_core.py +879 -0
- painapple_code/shadow_db.py +830 -0
- painapple_code/shadow_db_plans.py +369 -0
- painapple_code/shadow_db_queries.py +595 -0
- painapple_code/shadow_db_schema.py +676 -0
- painapple_code/shadow_git.py +1296 -0
- painapple_code/shadow_git_frontmatter.py +314 -0
- painapple_code/shadow_git_sections.py +520 -0
- painapple_code/shadow_git_summary.py +462 -0
- painapple_code/shadow_parser.py +560 -0
- painapple_code/static/css/00-variables.css +276 -0
- painapple_code/static/css/01-base.css +245 -0
- painapple_code/static/css/02-tooltips.css +36 -0
- painapple_code/static/css/09-left-rail.css +448 -0
- painapple_code/static/css/10-header.css +777 -0
- painapple_code/static/css/11-connection-bar.css +120 -0
- painapple_code/static/css/20-messages.css +750 -0
- painapple_code/static/css/21-tool-blocks.css +2340 -0
- painapple_code/static/css/22-edit-diff.css +619 -0
- painapple_code/static/css/23-thinking.css +1584 -0
- painapple_code/static/css/24-background-tasks.css +359 -0
- painapple_code/static/css/25-context-block.css +252 -0
- painapple_code/static/css/26-session-setup.css +144 -0
- painapple_code/static/css/30-markdown.css +854 -0
- painapple_code/static/css/40-input.css +2418 -0
- painapple_code/static/css/41-autocomplete.css +127 -0
- painapple_code/static/css/42-activity-strip.css +97 -0
- painapple_code/static/css/43-file-autocomplete.css +121 -0
- painapple_code/static/css/44-snippets-autocomplete.css +224 -0
- painapple_code/static/css/45-selection-bar.css +433 -0
- painapple_code/static/css/46-keyboard-bar.css +119 -0
- painapple_code/static/css/47-keyboard-longpress.css +116 -0
- painapple_code/static/css/47-token-profile.css +106 -0
- painapple_code/static/css/50-welcome.css +3095 -0
- painapple_code/static/css/51-modals.css +301 -0
- painapple_code/static/css/52-utilities.css +77 -0
- painapple_code/static/css/53-image-upload.css +456 -0
- painapple_code/static/css/54-todo-list.css +102 -0
- painapple_code/static/css/55-file-upload.css +113 -0
- painapple_code/static/css/56-chat-navigator.css +218 -0
- painapple_code/static/css/56-permission-card.css +332 -0
- painapple_code/static/css/56-plan-approval.css +204 -0
- painapple_code/static/css/56-question-form.css +602 -0
- painapple_code/static/css/57-swipe-indicator.css +95 -0
- painapple_code/static/css/58-session-families.css +627 -0
- painapple_code/static/css/59-about.css +196 -0
- painapple_code/static/css/61-log-explorer.css +723 -0
- painapple_code/static/css/62-json-tree.css +489 -0
- painapple_code/static/css/62-skills-widget.css +650 -0
- painapple_code/static/css/63-commands-widget.css +30 -0
- painapple_code/static/css/63-plugins-widget.css +174 -0
- painapple_code/static/css/63-terminal.css +516 -0
- painapple_code/static/css/64-search-files-widget.css +448 -0
- painapple_code/static/css/65-snippets-widget.css +426 -0
- painapple_code/static/css/66-active-sessions.css +979 -0
- painapple_code/static/css/66-agents-widget.css +265 -0
- painapple_code/static/css/66-file-explorer-widget.css +855 -0
- painapple_code/static/css/66-git-panel.css +791 -0
- painapple_code/static/css/66-history-explorer.css +1496 -0
- painapple_code/static/css/67-diff-viewer.css +602 -0
- painapple_code/static/css/67-editor-view.css +748 -0
- painapple_code/static/css/67-file-preview-widget.css +1873 -0
- painapple_code/static/css/68-browser-widget.css +337 -0
- painapple_code/static/css/68-compare-wizard.css +355 -0
- painapple_code/static/css/68-csv-preview.css +106 -0
- painapple_code/static/css/68-diff-preview.css +103 -0
- painapple_code/static/css/68-helpers-install-widget.css +491 -0
- painapple_code/static/css/68-image-annotate.css +346 -0
- painapple_code/static/css/68-terminal-view.css +98 -0
- painapple_code/static/css/68-uploads-widget.css +229 -0
- painapple_code/static/css/69-cost-analytics.css +537 -0
- painapple_code/static/css/70-config-panel.css +3736 -0
- painapple_code/static/css/70-excalidraw.css +136 -0
- painapple_code/static/css/70-prompt-explorer.css +890 -0
- painapple_code/static/css/71-chart.css +111 -0
- painapple_code/static/css/72-discussion-sidebar.css +678 -0
- painapple_code/static/css/74-debug-logs.css +656 -0
- painapple_code/static/css/80-open-dialog.css +146 -0
- painapple_code/static/css/80-quick-switcher.css +383 -0
- painapple_code/static/css/80-widget-system.css +1763 -0
- painapple_code/static/css/81-quick-actions.css +1020 -0
- painapple_code/static/css/82-context-popover.css +1233 -0
- painapple_code/static/css/83-context-menu.css +339 -0
- painapple_code/static/css/85-lazy-loading.css +102 -0
- painapple_code/static/css/86-zen-mode.css +708 -0
- painapple_code/static/css/87-grid-switcher.css +346 -0
- painapple_code/static/css/login.css +198 -0
- painapple_code/static/dist/app.bundle.js +7177 -0
- painapple_code/static/feature-triage.html +446 -0
- painapple_code/static/icons/apple-touch-icon.png +0 -0
- painapple_code/static/icons/favicon-32.png +0 -0
- painapple_code/static/icons/favicon.ico +0 -0
- painapple_code/static/icons/icon-128.png +0 -0
- painapple_code/static/icons/icon-144.png +0 -0
- painapple_code/static/icons/icon-152.png +0 -0
- painapple_code/static/icons/icon-180.png +0 -0
- painapple_code/static/icons/icon-192.png +0 -0
- painapple_code/static/icons/icon-384.png +0 -0
- painapple_code/static/icons/icon-512.png +0 -0
- painapple_code/static/icons/icon-72.png +0 -0
- painapple_code/static/icons/icon-96.png +0 -0
- painapple_code/static/js/action-delegate.js +187 -0
- painapple_code/static/js/activity-strip.js +193 -0
- painapple_code/static/js/app/context-menus.js +619 -0
- painapple_code/static/js/app/file-preview.js +163 -0
- painapple_code/static/js/app/init-ui.js +574 -0
- painapple_code/static/js/app/input-events.js +561 -0
- painapple_code/static/js/app/input-resize.js +313 -0
- painapple_code/static/js/app/message-actions.js +419 -0
- painapple_code/static/js/app/panels.js +210 -0
- painapple_code/static/js/app/rendering-delegators.js +246 -0
- painapple_code/static/js/app/server-loading.js +365 -0
- painapple_code/static/js/app/session-ops.js +287 -0
- painapple_code/static/js/app/session-switch.js +443 -0
- painapple_code/static/js/app/settings-helpers.js +280 -0
- painapple_code/static/js/app/startup-welcome.js +290 -0
- painapple_code/static/js/app-context.js +157 -0
- painapple_code/static/js/app.js +2134 -0
- painapple_code/static/js/auth-fetch.js +46 -0
- painapple_code/static/js/background-tasks.js +274 -0
- painapple_code/static/js/boot.js +73 -0
- painapple_code/static/js/caret-position.js +171 -0
- painapple_code/static/js/chat-navigator.js +710 -0
- painapple_code/static/js/chat-search.js +323 -0
- painapple_code/static/js/command-executor.js +176 -0
- painapple_code/static/js/command-store.js +497 -0
- painapple_code/static/js/components.js +1414 -0
- painapple_code/static/js/config.js +218 -0
- painapple_code/static/js/context-menu.js +740 -0
- painapple_code/static/js/controllers/chat-controller.js +4252 -0
- painapple_code/static/js/controllers/dialog-controller.js +217 -0
- painapple_code/static/js/controllers/tab-controller.js +1828 -0
- painapple_code/static/js/controllers/thinking-controller.js +915 -0
- painapple_code/static/js/diff-utils.js +486 -0
- painapple_code/static/js/drafts-pill.js +95 -0
- painapple_code/static/js/editor-view.js +815 -0
- painapple_code/static/js/effort-settings.js +430 -0
- painapple_code/static/js/feature-triage.js +811 -0
- painapple_code/static/js/file-autocomplete.js +516 -0
- painapple_code/static/js/file-tabs.js +123 -0
- painapple_code/static/js/gestures.js +448 -0
- painapple_code/static/js/grid-switcher.js +334 -0
- painapple_code/static/js/input-handler.js +1472 -0
- painapple_code/static/js/keyboard-bar.js +495 -0
- painapple_code/static/js/layout-switcher.js +109 -0
- painapple_code/static/js/linkify-utils.js +200 -0
- painapple_code/static/js/login.js +141 -0
- painapple_code/static/js/open-dialog.js +879 -0
- painapple_code/static/js/orphan-terminals.js +373 -0
- painapple_code/static/js/path-utils.js +179 -0
- painapple_code/static/js/perf-marks.js +102 -0
- painapple_code/static/js/permission-settings.js +475 -0
- painapple_code/static/js/pointer-input.js +59 -0
- painapple_code/static/js/preview/json-tree-menu.js +226 -0
- painapple_code/static/js/preview/json-tree-toolbar.js +291 -0
- painapple_code/static/js/preview/json-tree.js +457 -0
- painapple_code/static/js/preview/preview-breadcrumb.js +387 -0
- painapple_code/static/js/preview/preview-edit.js +367 -0
- painapple_code/static/js/preview/preview-events.js +361 -0
- painapple_code/static/js/preview/preview-history.js +567 -0
- painapple_code/static/js/preview/preview-inline-edit.js +869 -0
- painapple_code/static/js/preview/preview-poll.js +108 -0
- painapple_code/static/js/preview/preview-render.js +572 -0
- painapple_code/static/js/preview/preview-search.js +421 -0
- painapple_code/static/js/preview/preview-state.js +256 -0
- painapple_code/static/js/preview/preview-utils.js +251 -0
- painapple_code/static/js/preview-plugins/chart-plugin.js +22 -0
- painapple_code/static/js/preview-plugins/csv-plugin.js +188 -0
- painapple_code/static/js/preview-plugins/diff-plugin.js +258 -0
- painapple_code/static/js/preview-plugins/excalidraw-plugin.js +25 -0
- painapple_code/static/js/preview-plugins/html-plugin.js +104 -0
- painapple_code/static/js/preview-plugins/image-plugin.js +20 -0
- painapple_code/static/js/preview-plugins/index.js +34 -0
- painapple_code/static/js/preview-plugins/json-plugin.js +99 -0
- painapple_code/static/js/preview-plugins/jsonl-plugin.js +152 -0
- painapple_code/static/js/preview-plugins/markdown-plugin.js +266 -0
- painapple_code/static/js/preview-plugins/panzoom-plugin.js +63 -0
- painapple_code/static/js/preview-plugins/plugin-helpers.js +282 -0
- painapple_code/static/js/project-color-picker.js +110 -0
- painapple_code/static/js/project-colors.js +163 -0
- painapple_code/static/js/prompt-favorites.js +187 -0
- painapple_code/static/js/quick-actions-menu.js +1736 -0
- painapple_code/static/js/quick-actions-registry.js +1239 -0
- painapple_code/static/js/quick-switcher/controller.js +294 -0
- painapple_code/static/js/quick-switcher/fuzzy-scorer.js +123 -0
- painapple_code/static/js/quick-switcher/index.js +30 -0
- painapple_code/static/js/quick-switcher/providers/base-provider.js +51 -0
- painapple_code/static/js/quick-switcher/providers/command-provider.js +56 -0
- painapple_code/static/js/quick-switcher/providers/file-provider.js +291 -0
- painapple_code/static/js/quick-switcher/providers/panel-provider.js +132 -0
- painapple_code/static/js/quick-switcher/providers/project-provider.js +361 -0
- painapple_code/static/js/quick-switcher/providers/read-files-provider.js +104 -0
- painapple_code/static/js/quick-switcher/providers/skills-provider.js +129 -0
- painapple_code/static/js/quick-switcher/registry.js +69 -0
- painapple_code/static/js/quick-switcher/ui/item.js +54 -0
- painapple_code/static/js/quick-switcher/ui/picker.js +464 -0
- painapple_code/static/js/recent-opens.js +40 -0
- painapple_code/static/js/scroll-manager.js +530 -0
- painapple_code/static/js/scroll-state-machine.js +359 -0
- painapple_code/static/js/selection/action-bar.js +793 -0
- painapple_code/static/js/selection/index.js +15 -0
- painapple_code/static/js/selection/selection-handler.js +877 -0
- painapple_code/static/js/selection/state.js +181 -0
- painapple_code/static/js/session/agent-progress.js +202 -0
- painapple_code/static/js/session/handle-agent-message.js +481 -0
- painapple_code/static/js/session/handle-message.js +550 -0
- painapple_code/static/js/session/interactive.js +587 -0
- painapple_code/static/js/session/message-store.js +271 -0
- painapple_code/static/js/session/messages.js +253 -0
- painapple_code/static/js/session/persistence.js +179 -0
- painapple_code/static/js/session/restore.js +136 -0
- painapple_code/static/js/session/sync.js +333 -0
- painapple_code/static/js/session-container-pool.js +371 -0
- painapple_code/static/js/session-setup-panel.js +274 -0
- painapple_code/static/js/session.js +1047 -0
- painapple_code/static/js/shortcut-hints.js +272 -0
- painapple_code/static/js/shortcuts.js +1146 -0
- painapple_code/static/js/skills-autocomplete.js +262 -0
- painapple_code/static/js/snippets-autocomplete.js +738 -0
- painapple_code/static/js/stash-refs-view.js +83 -0
- painapple_code/static/js/stash-ui.js +768 -0
- painapple_code/static/js/stash.js +785 -0
- painapple_code/static/js/status-bar.js +1184 -0
- painapple_code/static/js/token-profile.js +274 -0
- painapple_code/static/js/tool-renderer-blocks.js +1626 -0
- painapple_code/static/js/tool-renderer-thinking.js +813 -0
- painapple_code/static/js/tool-renderer.js +1500 -0
- painapple_code/static/js/tooltips.js +197 -0
- painapple_code/static/js/upload-manager.js +1019 -0
- painapple_code/static/js/utils.js +521 -0
- painapple_code/static/js/welcome/api.js +363 -0
- painapple_code/static/js/welcome/cards.js +626 -0
- painapple_code/static/js/welcome/context-menu.js +585 -0
- painapple_code/static/js/welcome/families.js +801 -0
- painapple_code/static/js/welcome/preview.js +234 -0
- painapple_code/static/js/welcome/state.js +129 -0
- painapple_code/static/js/welcome.js +1874 -0
- painapple_code/static/js/widget-system/base-widget.js +717 -0
- painapple_code/static/js/widget-system/device-manager.js +178 -0
- painapple_code/static/js/widget-system/event-bus.js +152 -0
- painapple_code/static/js/widget-system/icons.js +120 -0
- painapple_code/static/js/widget-system/index.js +49 -0
- painapple_code/static/js/widget-system/init.js +54 -0
- painapple_code/static/js/widget-system/types/bottom-sheet.js +307 -0
- painapple_code/static/js/widget-system/types/floating.js +915 -0
- painapple_code/static/js/widget-system/types/index.js +40 -0
- painapple_code/static/js/widget-system/types/modal.js +147 -0
- painapple_code/static/js/widget-system/types/sidebar.js +158 -0
- painapple_code/static/js/widget-system/types/tab.js +146 -0
- painapple_code/static/js/widget-system/types/top-sheet.js +203 -0
- painapple_code/static/js/widget-system/widget-manager.js +1187 -0
- painapple_code/static/js/widgets/about-widget.js +260 -0
- painapple_code/static/js/widgets/active-sessions-widget.js +760 -0
- painapple_code/static/js/widgets/agents-widget.js +897 -0
- painapple_code/static/js/widgets/browser-widget.js +579 -0
- painapple_code/static/js/widgets/commands-widget.js +694 -0
- painapple_code/static/js/widgets/config/commit-sections.js +449 -0
- painapple_code/static/js/widgets/config/dir-autocomplete.js +224 -0
- painapple_code/static/js/widgets/config/gestures.js +161 -0
- painapple_code/static/js/widgets/config/models-tab.js +988 -0
- painapple_code/static/js/widgets/config/quick-actions-tab.js +882 -0
- painapple_code/static/js/widgets/config/shortcut-editor.js +587 -0
- painapple_code/static/js/widgets/config/state.js +517 -0
- painapple_code/static/js/widgets/config/system-controls.js +90 -0
- painapple_code/static/js/widgets/config-widget.js +1535 -0
- painapple_code/static/js/widgets/cost-analytics-widget.js +621 -0
- painapple_code/static/js/widgets/debug-widget.js +693 -0
- painapple_code/static/js/widgets/diff-viewer-widget.js +1420 -0
- painapple_code/static/js/widgets/discussion-widget.js +1107 -0
- painapple_code/static/js/widgets/file-explorer-widget.js +2166 -0
- painapple_code/static/js/widgets/file-preview-widget.js +861 -0
- painapple_code/static/js/widgets/git-widget.js +794 -0
- painapple_code/static/js/widgets/helpers-install-widget.js +720 -0
- painapple_code/static/js/widgets/history-explorer-widget.js +1804 -0
- painapple_code/static/js/widgets/image-annotate-widget.js +951 -0
- painapple_code/static/js/widgets/image-preview-widget.js +692 -0
- painapple_code/static/js/widgets/index.js +176 -0
- painapple_code/static/js/widgets/log-explorer-widget.js +1057 -0
- painapple_code/static/js/widgets/plugins-widget.js +305 -0
- painapple_code/static/js/widgets/prompt-explorer-widget.js +1119 -0
- painapple_code/static/js/widgets/search-files-widget.js +529 -0
- painapple_code/static/js/widgets/skills-widget.js +843 -0
- painapple_code/static/js/widgets/snippets-widget.js +479 -0
- painapple_code/static/js/widgets/sub-agents-widget.js +333 -0
- painapple_code/static/js/widgets/tasks-widget.js +379 -0
- painapple_code/static/js/widgets/terminal/connection.js +283 -0
- painapple_code/static/js/widgets/terminal/gestures.js +357 -0
- painapple_code/static/js/widgets/terminal/init.js +642 -0
- painapple_code/static/js/widgets/terminal/link-providers.js +532 -0
- painapple_code/static/js/widgets/terminal/osc52.js +213 -0
- painapple_code/static/js/widgets/terminal/render.js +159 -0
- painapple_code/static/js/widgets/terminal/size.js +54 -0
- painapple_code/static/js/widgets/terminal/state.js +211 -0
- painapple_code/static/js/widgets/terminal/wrap-utils.js +101 -0
- painapple_code/static/js/widgets/terminal-widget.js +793 -0
- painapple_code/static/js/widgets/uploads-widget.js +461 -0
- painapple_code/static/js/widgets/zen-widget.js +1001 -0
- painapple_code/static/login.html +51 -0
- painapple_code/static/manifest.json +73 -0
- painapple_code/static/sw.js +293 -0
- painapple_code/static/vendor/LICENSES.txt +769 -0
- painapple_code/static/vendor/README.md +103 -0
- painapple_code/static/vendor/codemirror.js +35 -0
- painapple_code/static/vendor/codemirror.js.LEGAL.txt +304 -0
- painapple_code/static/vendor/github-markdown-dark.min.css +1124 -0
- painapple_code/static/vendor/highlight-github-dark.min.css +10 -0
- painapple_code/static/vendor/highlight-lang-dockerfile.min.js +8 -0
- painapple_code/static/vendor/highlight-lang-nginx.min.js +21 -0
- painapple_code/static/vendor/highlight-lang-properties.min.js +10 -0
- painapple_code/static/vendor/highlight-lang-scala.min.js +28 -0
- painapple_code/static/vendor/highlight.min.js +1213 -0
- painapple_code/static/vendor/marked.min.js +6 -0
- painapple_code/static/vendor/purify.min.js +3 -0
- painapple_code/static/vendor/xterm-addon-fit.js +2 -0
- painapple_code/static/vendor/xterm.css +209 -0
- painapple_code/static/vendor/xterm.js +2 -0
- painapple_code/static/web-client.html +635 -0
- painapple_code/subprocess_registry.py +535 -0
- painapple_code/tls_cert.py +79 -0
- painapple_code/tools/agents/shadow-git-helper.md +400 -0
- painapple_code/tools/excalidraw-to-svg.js +143 -0
- painapple_code/tools/install-helpers.sh +148 -0
- painapple_code/tools/shadow-git +320 -0
- painapple_code/tools/shadow-query +120 -0
- painapple_code/tools/vegalite-to-svg.js +79 -0
- painapple_code/turn_query.py +766 -0
- painapple_code/turn_tracker.py +221 -0
- painapple_code/utils/__init__.py +0 -0
- painapple_code/utils/agent_cli.py +306 -0
- painapple_code/utils/chart.py +103 -0
- painapple_code/utils/excalidraw.py +107 -0
- painapple_code/utils/file_lock.py +162 -0
- painapple_code/utils/file_paths.py +648 -0
- painapple_code/utils/generate_icons.py +251 -0
- painapple_code/utils/proc.py +205 -0
- painapple_code/utils/pty_backend.py +59 -0
- painapple_code/utils/pty_posix.py +160 -0
- painapple_code/utils/pty_windows.py +245 -0
- painapple_code/utils/token_profiles.py +91 -0
- painapple_code/viewer_templates.py +657 -0
- painapple_code/welcome_search.py +879 -0
- painapple_code-1.0.0.dist-info/METADATA +292 -0
- painapple_code-1.0.0.dist-info/RECORD +436 -0
- painapple_code-1.0.0.dist-info/WHEEL +5 -0
- painapple_code-1.0.0.dist-info/entry_points.txt +2 -0
- painapple_code-1.0.0.dist-info/licenses/LICENSE +661 -0
- painapple_code-1.0.0.dist-info/licenses/THIRD_PARTY_NOTICES.md +261 -0
- painapple_code-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
"""Persistent global serve defaults — the store behind ``painapple setup``.
|
|
2
|
+
|
|
3
|
+
``$PAINAPPLE_CODE_HOME/serve.yaml`` (default ``~/.painapple-code/
|
|
4
|
+
serve.yaml``) holds the *global* defaults for a bare ``painapple
|
|
5
|
+
[serve]`` invocation:
|
|
6
|
+
|
|
7
|
+
* network: ``host``, ``port``, ``tls`` (argparse dests, layered via
|
|
8
|
+
``parser.set_defaults()`` — built-ins < serve.yaml < explicit flags)
|
|
9
|
+
* container runtime: ``runtime``, ``runtime_flags``, ``image`` — read
|
|
10
|
+
by the ``--in-docker`` launch path, never by the host server.
|
|
11
|
+
|
|
12
|
+
Workspace and cosmetics (``workspace``, ``instance_name``,
|
|
13
|
+
``accent``) are PROFILE-ONLY concepts since the CLI
|
|
14
|
+
unification: a bare ``painapple`` always serves the current directory,
|
|
15
|
+
and a label/accent only makes sense on a named deployment
|
|
16
|
+
(``painapple setup NAME`` — see cli/profiles.py). Those keys in the
|
|
17
|
+
root serve.yaml are ignored with a warning; in a profile's
|
|
18
|
+
``profile.yaml`` they're first-class.
|
|
19
|
+
|
|
20
|
+
Deliberately NOT read by the fast gate in ``cli.main()`` — the gate
|
|
21
|
+
only validates flag syntax, values don't matter there — so this module
|
|
22
|
+
(and its yaml import) stays off the ``-v``/``--help`` fast path.
|
|
23
|
+
``server.main()`` applies the file right before its re-parse.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
import os
|
|
27
|
+
import re
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
|
|
30
|
+
# KEEP IN SYNC with COLOR_PRESETS in server.py (the --accent vocabulary).
|
|
31
|
+
ACCENT_PRESETS = ("blue", "green", "red", "orange", "purple", "cyan",
|
|
32
|
+
"gray", "grey", "yellow", "pink", "teal", "indigo", "lime")
|
|
33
|
+
_HEX_RE = re.compile(r"^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$")
|
|
34
|
+
|
|
35
|
+
TLS_MODES = ("auto", "on", "off")
|
|
36
|
+
INSTANCE_NAME_MAX = 12
|
|
37
|
+
|
|
38
|
+
# Full host-mode key vocabulary (validated by _check). Profile files may
|
|
39
|
+
# carry all of these; the ROOT serve.yaml only honors GLOBAL_KEYS.
|
|
40
|
+
HOST_KEYS = ("workspace", "host", "port", "tls",
|
|
41
|
+
"instance_name", "accent")
|
|
42
|
+
KEYS = HOST_KEYS # historical alias
|
|
43
|
+
|
|
44
|
+
GLOBAL_KEYS = ("host", "port", "tls")
|
|
45
|
+
DEPLOY_KEYS = ("runtime", "runtime_flags", "image") # --in-docker defaults
|
|
46
|
+
ROOT_KEYS = GLOBAL_KEYS + DEPLOY_KEYS
|
|
47
|
+
PROFILE_ONLY_KEYS = ("workspace", "instance_name", "accent")
|
|
48
|
+
|
|
49
|
+
# Unified profile store directory (see cli/profiles.py) + the two legacy
|
|
50
|
+
# generations it adopts. Constants live HERE (import-light) so the
|
|
51
|
+
# fast-path callers (list_cmd name defaulting, activate nesting guard)
|
|
52
|
+
# don't need cli/profiles.py.
|
|
53
|
+
PROFILES_DIR = "profiles"
|
|
54
|
+
LEGACY_SERVE_PROFILES_DIR = "serve-profiles"
|
|
55
|
+
LEGACY_DOCKER_PROFILES_DIR = "docker-profiles"
|
|
56
|
+
PROFILE_PARENT_DIRS = (PROFILES_DIR, LEGACY_SERVE_PROFILES_DIR)
|
|
57
|
+
_PROFILE_PARENT_DIRS = PROFILE_PARENT_DIRS # internal alias
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def home_root():
|
|
61
|
+
"""The data home THIS process uses — env override or
|
|
62
|
+
``~/.painapple-code``. Under an activated profile this IS the
|
|
63
|
+
profile's home; use :func:`root_home` for the box-wide root."""
|
|
64
|
+
return Path(os.environ.get("PAINAPPLE_CODE_HOME",
|
|
65
|
+
"~/.painapple-code")).expanduser()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def root_home():
|
|
69
|
+
"""The box-wide root data home, climbing out of an activated
|
|
70
|
+
profile's home (``…/profiles/NAME`` → ``…``). Shared resources
|
|
71
|
+
(the profile store itself, shared/.claude) always live here."""
|
|
72
|
+
home = home_root()
|
|
73
|
+
if home.parent.name in _PROFILE_PARENT_DIRS:
|
|
74
|
+
return home.parent.parent
|
|
75
|
+
return home
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def serve_yaml_path():
|
|
79
|
+
return home_root() / "serve.yaml"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def valid_profile_name(name):
|
|
83
|
+
return bool(_PROFILE_RE.match((name or "").strip()))
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
_PROFILE_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]{0,31}$")
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def extract_profile(argv):
|
|
90
|
+
"""``(profile, rest)``: strip ``--profile NAME`` / ``--profile=NAME``
|
|
91
|
+
from anywhere in ``argv`` (before or after a subcommand), falling back
|
|
92
|
+
to ``$PAINAPPLE_PROFILE``. ``profile`` is None when absent. Raises
|
|
93
|
+
ValueError on a dangling ``--profile`` with no value."""
|
|
94
|
+
prof, rest, i = None, [], 0
|
|
95
|
+
while i < len(argv):
|
|
96
|
+
arg = argv[i]
|
|
97
|
+
if arg == "--profile":
|
|
98
|
+
if i + 1 >= len(argv):
|
|
99
|
+
raise ValueError("Missing value for --profile")
|
|
100
|
+
prof, i = argv[i + 1], i + 2
|
|
101
|
+
elif arg.startswith("--profile="):
|
|
102
|
+
prof, i = arg.split("=", 1)[1], i + 1
|
|
103
|
+
else:
|
|
104
|
+
rest.append(arg)
|
|
105
|
+
i += 1
|
|
106
|
+
if prof is None:
|
|
107
|
+
prof = os.environ.get("PAINAPPLE_PROFILE") or None
|
|
108
|
+
return prof, rest
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _check(key, value):
|
|
112
|
+
"""Normalized value, or raises ValueError with a human reason."""
|
|
113
|
+
if key == "port":
|
|
114
|
+
if isinstance(value, str) and value.isdigit():
|
|
115
|
+
value = int(value)
|
|
116
|
+
if not (isinstance(value, int) and not isinstance(value, bool)
|
|
117
|
+
and 1 <= value <= 65535):
|
|
118
|
+
raise ValueError(f"port must be a number 1-65535, got {value!r}")
|
|
119
|
+
return value
|
|
120
|
+
if not isinstance(value, str) or not value.strip():
|
|
121
|
+
raise ValueError(f"{key} must be a non-empty string, got {value!r}")
|
|
122
|
+
value = value.strip()
|
|
123
|
+
if key == "tls" and value not in TLS_MODES:
|
|
124
|
+
raise ValueError(f"tls must be one of {'/'.join(TLS_MODES)}, got {value!r}")
|
|
125
|
+
if key == "instance_name" and len(value) > INSTANCE_NAME_MAX:
|
|
126
|
+
raise ValueError(f"instance_name too long ({len(value)} chars, "
|
|
127
|
+
f"max {INSTANCE_NAME_MAX})")
|
|
128
|
+
if key == "accent" and value not in ACCENT_PRESETS and not _HEX_RE.match(value):
|
|
129
|
+
raise ValueError(f"accent must be a preset "
|
|
130
|
+
f"({', '.join(ACCENT_PRESETS[:6])}, …) or a hex "
|
|
131
|
+
f"color like #f87171, got {value!r}")
|
|
132
|
+
if key == "runtime" and value not in ("docker", "podman"):
|
|
133
|
+
expanded = str(Path(value).expanduser())
|
|
134
|
+
if not (Path(expanded).is_absolute() and Path(expanded).is_file()):
|
|
135
|
+
raise ValueError(
|
|
136
|
+
"runtime must be 'docker', 'podman', or an absolute path "
|
|
137
|
+
f"to a runtime binary, got {value!r}")
|
|
138
|
+
return expanded
|
|
139
|
+
return value
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def load(path=None, recognized=None):
|
|
143
|
+
"""(values, problems): the file's valid key→value pairs, plus a list
|
|
144
|
+
of human-readable strings for anything skipped. Missing/unreadable
|
|
145
|
+
file → ({}, []) and ({}, [reason]) respectively — never raises.
|
|
146
|
+
``path`` overrides the default location (`painapple list` resolves a
|
|
147
|
+
per-process config from each server's own PAINAPPLE_CODE_HOME);
|
|
148
|
+
``recognized`` narrows the accepted key set (default: everything)."""
|
|
149
|
+
path = path or serve_yaml_path()
|
|
150
|
+
if not path.is_file():
|
|
151
|
+
return {}, []
|
|
152
|
+
import yaml
|
|
153
|
+
try:
|
|
154
|
+
data = yaml.safe_load(path.read_text(encoding="utf-8"))
|
|
155
|
+
except (OSError, yaml.YAMLError) as e:
|
|
156
|
+
return {}, [f"unreadable ({e}) — using built-in defaults"]
|
|
157
|
+
if data is None:
|
|
158
|
+
return {}, []
|
|
159
|
+
if not isinstance(data, dict):
|
|
160
|
+
return {}, ["not a key: value mapping — using built-in defaults"]
|
|
161
|
+
recognized = recognized or (HOST_KEYS + DEPLOY_KEYS)
|
|
162
|
+
values, problems = {}, []
|
|
163
|
+
for key, value in data.items():
|
|
164
|
+
if key == "mode":
|
|
165
|
+
continue # profile.yaml marker — not a serve value
|
|
166
|
+
if key not in recognized:
|
|
167
|
+
problems.append(f"unknown key {key!r} ignored")
|
|
168
|
+
continue
|
|
169
|
+
try:
|
|
170
|
+
values[key] = _check(key, value)
|
|
171
|
+
except ValueError as e:
|
|
172
|
+
problems.append(f"{e} — key ignored")
|
|
173
|
+
return values, problems
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def save(values):
|
|
177
|
+
"""Write the ROOT serve.yaml from the recognized, non-empty entries
|
|
178
|
+
of ``values`` (global keys only — profile settings go through
|
|
179
|
+
cli/profiles.py). Returns the path written. An empty mapping removes
|
|
180
|
+
the file — bare ``painapple`` goes back to built-in defaults."""
|
|
181
|
+
import yaml
|
|
182
|
+
path = serve_yaml_path()
|
|
183
|
+
kept = {k: _check(k, values[k]) for k in ROOT_KEYS
|
|
184
|
+
if values.get(k) not in (None, "")}
|
|
185
|
+
if not kept:
|
|
186
|
+
path.unlink(missing_ok=True)
|
|
187
|
+
return path
|
|
188
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
189
|
+
body = yaml.safe_dump(kept, default_flow_style=False, sort_keys=False)
|
|
190
|
+
path.write_text(
|
|
191
|
+
"# Global serve defaults written by `painapple setup` — editable by hand.\n"
|
|
192
|
+
"# A bare `painapple` starts with these; explicit flags override.\n"
|
|
193
|
+
"# Named deployments live in profiles/NAME/profile.yaml (painapple setup NAME).\n"
|
|
194
|
+
+ body, encoding="utf-8")
|
|
195
|
+
return path
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def _active_profile_config_path():
|
|
199
|
+
"""The config file an ACTIVATED profile's server should layer:
|
|
200
|
+
``<home>/profile.yaml`` (unified store), falling back to the legacy
|
|
201
|
+
``<home>/serve.yaml`` for a not-yet-migrated profile home. None when
|
|
202
|
+
no profile is active."""
|
|
203
|
+
home = home_root()
|
|
204
|
+
prof = (os.environ.get("PAINAPPLE_PROFILE") or "").strip()
|
|
205
|
+
is_profile_home = home.parent.name in _PROFILE_PARENT_DIRS
|
|
206
|
+
if not (prof and prof != "default") and not is_profile_home:
|
|
207
|
+
return None
|
|
208
|
+
if (home / "profile.yaml").is_file():
|
|
209
|
+
return home / "profile.yaml"
|
|
210
|
+
return home / "serve.yaml"
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def active_config_path():
|
|
214
|
+
"""The file :func:`apply_to_parser` actually layers — an activated
|
|
215
|
+
profile's ``profile.yaml`` (or its legacy ``serve.yaml``), else the
|
|
216
|
+
global ``serve.yaml``. Logging ``serve_yaml_path()`` instead named a
|
|
217
|
+
file that doesn't exist under a profile."""
|
|
218
|
+
return _active_profile_config_path() or serve_yaml_path()
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def apply_to_parser(parser):
|
|
222
|
+
"""Install saved defaults as parser defaults. Returns the same
|
|
223
|
+
(values, problems) pair as :func:`load` so the caller can log what
|
|
224
|
+
was applied/skipped.
|
|
225
|
+
|
|
226
|
+
Root invocation: global serve.yaml, GLOBAL_KEYS only — a workspace
|
|
227
|
+
or cosmetics key left over from pre-unification files is reported
|
|
228
|
+
and skipped (bare ``painapple`` always serves the cwd).
|
|
229
|
+
Activated profile: the profile's own config, full host vocabulary.
|
|
230
|
+
"""
|
|
231
|
+
profile_cfg = _active_profile_config_path()
|
|
232
|
+
if profile_cfg is not None:
|
|
233
|
+
values, problems = load(profile_cfg, recognized=HOST_KEYS)
|
|
234
|
+
prof = (os.environ.get("PAINAPPLE_PROFILE") or "").strip()
|
|
235
|
+
if not prof or prof == "default":
|
|
236
|
+
prof = home_root().name
|
|
237
|
+
if prof and "instance_name" not in values:
|
|
238
|
+
# Default the UI label to the profile name so co-running
|
|
239
|
+
# profiles are distinguishable.
|
|
240
|
+
values = {**values, "instance_name": prof[:INSTANCE_NAME_MAX]}
|
|
241
|
+
if values:
|
|
242
|
+
parser.set_defaults(**values)
|
|
243
|
+
return values, problems
|
|
244
|
+
|
|
245
|
+
values, problems = load(recognized=HOST_KEYS + DEPLOY_KEYS)
|
|
246
|
+
for key in PROFILE_ONLY_KEYS:
|
|
247
|
+
if key in values:
|
|
248
|
+
values.pop(key)
|
|
249
|
+
problems.append(
|
|
250
|
+
f"key {key!r} is profile-only now (painapple setup NAME) — "
|
|
251
|
+
"ignored for the bare serve")
|
|
252
|
+
for key in DEPLOY_KEYS:
|
|
253
|
+
values.pop(key, None) # --in-docker settings, not server flags
|
|
254
|
+
if values:
|
|
255
|
+
parser.set_defaults(**values)
|
|
256
|
+
return values, problems
|