interlatch 0.29.2__tar.gz → 0.29.3__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.
- {interlatch-0.29.2 → interlatch-0.29.3}/CHANGELOG.md +13 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/PKG-INFO +1 -1
- interlatch-0.29.3/changelog.d/analysis-usage-footer.md +4 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/configuration.md +1 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/ja/configuration.md +1 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/analysis/queue.py +24 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/application/workflows.py +10 -5
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/core/config.py +4 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/core/i18n/ja.py +3 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/api/status.py +50 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/routes.py +1 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/app.css +28 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/app.js +88 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/index.html +2 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/ja.js +30 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_queue.py +60 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_route_matrix.py +1 -0
- interlatch-0.29.2/changelog.d/hub-glossary-members.md +0 -4
- interlatch-0.29.2/changelog.d/hub-project-page.md +0 -6
- {interlatch-0.29.2 → interlatch-0.29.3}/.github/dependabot.yml +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/.github/windows-ja-qa/driver.ps1 +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/.github/windows-ja-qa/ja_check.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/.github/windows-ja-qa/report.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/.github/windows-ja-qa/shots.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/.github/windows-ja-qa/user.ps1 +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/.github/workflows/changelog.yml +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/.github/workflows/ci.yml +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/.github/workflows/docs.yml +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/.github/workflows/release.yml +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/.github/workflows/windows-ja-qa.yml +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/.gitignore +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/.pre-commit-config.yaml +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/.python-version +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/CONTRIBUTING.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/LICENSE +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/README.ja.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/README.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/ROADMAP.ja.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/ROADMAP.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/SECURITY.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/careers/README.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/careers/boards.json +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/careers/pipeline.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/changelog.d/README.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/dev.sh +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docker/.dockerignore +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docker/.env.example +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docker/Caddyfile +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docker/Dockerfile +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docker/compose.yaml +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docker/wheels/.gitignore +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/README.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/_site/hooks.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/analysis.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/cli.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/dashboard.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/demo/make_demo.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/demo/record_demo.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/design/innerlatch.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/design/ja/innerlatch.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/design/ja/learning.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/design/learning.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/development.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/devices.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/diagrams/analysis.excalidraw.svg +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/diagrams/architecture.excalidraw.svg +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/docker.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/faq.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/images/demo.gif +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/images/group-connections.png +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/images/hero.png +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/images/home.png +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/images/job-goal.png +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/images/map.png +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/images/palette.png +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/images/session.png +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/install.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/ja/README.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/ja/analysis.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/ja/cli.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/ja/dashboard.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/ja/development.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/ja/devices.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/ja/docker.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/ja/faq.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/ja/install.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/ja/join-a-hub.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/ja/mcp.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/ja/moving-from-chronicle.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/ja/party.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/ja/postgres.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/ja/privacy.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/ja/profiles.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/ja/sources.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/ja/suggestions.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/ja/troubleshooting.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/ja/vscode.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/join-a-hub.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/mcp.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/moving-from-chronicle.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/party.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/postgres.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/privacy.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/profiles.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/sources.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/suggestions.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/troubleshooting.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/docs/vscode.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/leaderboard/.firebaserc +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/leaderboard/.gitignore +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/leaderboard/README.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/leaderboard/firebase.json +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/leaderboard/firestore.indexes.json +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/leaderboard/firestore.rules +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/mkdocs.yml +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/packaging/icons3d/README.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/packaging/icons3d/art.json +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/packaging/icons3d/filing.html +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/packaging/icons3d/loops.json +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/packaging/icons3d/loops.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/packaging/icons3d/members.js +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/packaging/icons3d/render.html +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/packaging/icons3d/render.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/packaging/icons3d/scenes-more.js +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/packaging/icons3d/scenes.html +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/packaging/macos/Chronicle.icns +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/packaging/macos/Interlatch.spec +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/packaging/macos/build.sh +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/packaging/macos/entitlements.plist +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/packaging/macos/icon-3d.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/packaging/macos/icon-blueprint-prompt.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/packaging/macos/icon-blueprint.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/packaging/macos/icon.png +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/packaging/macos/interlatch_app.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/packaging/macos/make_icon.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/packaging/release.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/pyproject.toml +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/chronicle/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/chronicle/__main__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/chronicle/windows.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/__main__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/analysis/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/analysis/digest.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/analysis/language.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/analysis/runners/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/analysis/runners/api.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/analysis/runners/base.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/analysis/runners/bob.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/analysis/runners/claude.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/analysis/runners/codex.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/analysis/runners/factory.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/analysis/runners/off.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/analysis/runners/opencode.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/analysis/runners/process.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/analysis/runners/replies.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/analysis/runners/settings.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/analysis/screen.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/analysis/session.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/analysis/worker.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/application/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/application/profiles.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/application/records.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/application/search.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/artifacts/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/artifacts/files.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/artifacts/queries.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/cli.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/core/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/core/agents.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/core/artifact_records.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/core/budget.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/core/diagrams.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/core/i18n/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/core/machine.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/core/paths.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/core/pricing.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/core/process.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/core/profiles.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/core/redact.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/core/sessions.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/core/util.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/ingestion/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/ingestion/analyses.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/ingestion/archive.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/ingestion/chat_import.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/ingestion/deletion.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/ingestion/history.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/ingestion/memory.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/ingestion/persistence.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/ingestion/report.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/ingestion/service.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/cli/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/cli/commands/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/cli/commands/archive.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/cli/commands/hubs.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/cli/commands/knowledge.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/cli/commands/operations.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/cli/commands/recording.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/cli/commands/setup.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/cli/commands/sharing.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/cli/common.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/cli/main.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/cli/parser.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/exports/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/exports/diagrams.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/exports/markdown.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/exports/sessions.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/exports/vault.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/mcp.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/api/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/api/artifacts.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/api/common.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/api/devices.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/api/hub_admin.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/api/hubs.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/api/knowledge.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/api/leaderboard.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/api/party.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/api/projects.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/api/sessions.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/api/settings.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/api/sources.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/api/storage.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/api/team.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/app.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/assets.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/context.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/handler.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/jobs.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/interfaces/web/server.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/arena.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/bag.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/cases.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/formation.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/freshness.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/friction.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/gates.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/glossary.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/group_graph.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/hero.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/instructions.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/interview.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/jobprep.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/jobs.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/ladder.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/learning.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/market.json +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/party.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/reviews.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/roadmap.json +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/study.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/suggest.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/synthesize.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/knowledge/weekly.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/projects/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/projects/groups.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/projects/hubgroups.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/projects/labels.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/projects/owners.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/projects/progress.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/projects/resume.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/projects/routing.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/projects/scope.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/projects/systems.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/projects/team.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/runtime/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/runtime/connectors.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/runtime/container.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/runtime/feedback.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/runtime/hooks.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/runtime/install.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/runtime/migrate.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/runtime/notify.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/runtime/platforms/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/runtime/platforms/desktop.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/runtime/platforms/menubar.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/runtime/platforms/windows.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/runtime/statusline.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/runtime/tailnet.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/runtime/update.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sharing/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sharing/access.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sharing/arena.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sharing/client.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sharing/identity.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sharing/leaderboard.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sharing/market.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sharing/membership.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sharing/news.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sharing/people.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sharing/projects.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sharing/protocol.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sharing/pull.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sharing/push.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sharing/receiver.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sources/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sources/antigravity.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sources/bob.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sources/builder.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sources/chatgpt.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sources/chats.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sources/claude/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sources/claude/export.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sources/claude/files.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sources/claude/parser.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sources/codex/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sources/codex/cloud.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sources/codex/parser.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sources/copilot.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sources/discovery.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sources/opencode.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/sources/prompts.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/storage/__init__.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/storage/fts.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/storage/kv.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/storage/migrations.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/storage/mirror.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/storage/postgres.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/storage/schema.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/storage/sqlite.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/storage/team.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/AGENT-ICONS.txt +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/PLEX-OFL.txt +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/adventure.js +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/agent-antigravity.svg +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/agent-bob.svg +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/agent-chatgpt.svg +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/agent-claude-ai.svg +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/agent-claude.svg +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/agent-codex.svg +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/agent-copilot.svg +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/agent-opencode.svg +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-book.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-camera.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-chip.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-clock.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-cloud.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-coins.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-container.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-dashboard.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-dex.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-document.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-flag.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-folder.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-gateway.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-gears.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-glitch.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-globe.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-laptop.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-log.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-lumi.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-magnifier.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-pip.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-plug.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-rack.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/art-tink.webp +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/battle.js +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/boot.js +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/favicon.png +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/field.js +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/i18n.js +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/icon-180.png +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/icon-192.png +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/icon-512.png +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/icon.png +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/innerlatch.css +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/innerlatch.js +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/learning.js +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/manifest.webmanifest +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/panel.css +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/panel.html +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/panel.js +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/plex-mono-400.woff2 +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/plex-mono-500.woff2 +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/plex-mono-600.woff2 +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/plex-sans-400.woff2 +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/plex-sans-500.woff2 +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/plex-sans-600.woff2 +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/plex-sans-700.woff2 +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/rough.js +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/scene.js +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/signin.js +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/web/sprites.js +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/src/interlatch/windows.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/antigravity_fixture.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/codex_fixture.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/conftest.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/copilot_fixture.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/fixtures/db/0.21.3/chronicle.db +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/fixtures/db/0.21.3/expected.json +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/fixtures/db/0.27.8/chronicle.db +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/fixtures/db/0.27.8/expected.json +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/fixtures/db/0.5.0/chronicle.db +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/fixtures/db/0.5.0/expected.json +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/fixtures/db/README.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/fixtures/db/make_fixture.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/friction_fixture.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/golden.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/goldens/cli.json +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/goldens/diagram.json +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/goldens/parsers/antigravity.json +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/goldens/parsers/bob.json +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/goldens/parsers/claude_code.json +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/goldens/parsers/codex.json +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/goldens/parsers/copilot.json +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/goldens/parsers/opencode.json +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/goldens/systems.json +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/hubs_fixture.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/opencode_fixture.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_adventure_web.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_analysis.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_antigravity.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_architecture.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_arena.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_artifacts.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_bag.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_battle_web.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_bob_analysis.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_boot_web.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_careers.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_case_files.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_cases.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_chat_import.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_cli_pins.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_codex.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_codex_analysis.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_codex_cloud.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_container.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_copilot_bob.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_db_compat.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_dedicated_hub.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_dedupe.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_desktop.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_diagram.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_doctor_agents.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_ee_boundary.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_feedback.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_field_web.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_fix_effect.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_formation.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_friction.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_game_mode.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_gates.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_glossary.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_group_graph.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_group_sharing.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_guidance.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_hero.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_home_agents.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_hub.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_hub_accept.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_hub_cookie.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_hub_groups.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_hub_inventory_scope.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_hub_leave_join.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_hub_news.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_hub_payload_privacy.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_hub_projects.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_hub_projects_listed.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_hub_purge.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_hub_send_problems.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_hub_sharing_race.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_i18n_web.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_ingest.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_instructions.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_integration.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_interview.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_jobprep.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_jobs.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_knowledge_freshness.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_ladder.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_language.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_leaderboard.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_learning_glance.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_learning_interests.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_learning_web.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_leave_project.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_legacy_package.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_map_goldens.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_market.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_mcp_resume.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_menubar.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_migrate.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_mirror.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_notify.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_opencode.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_opencode_analysis.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_parser.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_parser_goldens.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_party.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_party_map.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_people.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_people_hub.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_people_web.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_profile_hubs.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_profile_scope.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_profiles.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_project_groups.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_project_progress.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_project_team.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_providers.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_regressions.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_release.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_roadmap_catalog.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_screen.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_security.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_session_context_budget.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_setup.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_statusline.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_study.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_suggest.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_suggest_cli.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_systems.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_team.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_team_home.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_update.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_weekly_reanalysis.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/test_windows.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/tests/windows_smoke.py +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/uv.lock +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/vscode-extension/.vscodeignore +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/vscode-extension/LICENSE +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/vscode-extension/README.md +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/vscode-extension/extension.js +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/vscode-extension/media/icon.png +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/vscode-extension/media/interlatch.svg +0 -0
- {interlatch-0.29.2 → interlatch-0.29.3}/vscode-extension/package.json +0 -0
|
@@ -3,6 +3,19 @@
|
|
|
3
3
|
<!-- Don't add lines here: a pull request puts its line in a new file in changelog.d/ (see changelog.d/README.md),
|
|
4
4
|
and each release moves the files it took into a dated section below. -->
|
|
5
5
|
|
|
6
|
+
## 0.29.2 (2026-10-29)
|
|
7
|
+
|
|
8
|
+
- **A project's page on a team hub:** the team's knowledge leads. Each knowledge base entry and lesson names whose
|
|
9
|
+
sessions taught it, lessons two people found separately sit side by side, **Since your last visit** lists new and
|
|
10
|
+
replaced lessons, **Start here** greets someone new to the project, **People** shows who has worked on what (never
|
|
11
|
+
a count per person), and **Who's working on it** draws each person's sessions over eight weeks. Tokens and cost
|
|
12
|
+
move to an admin-only Usage tab, and the Systems map is no longer offered where it would be empty or refused
|
|
13
|
+
([On a team hub](docs/dashboard.md#on-a-team-hub)).
|
|
14
|
+
- **A project's glossary and mindmap on a team hub:** a project's page there has a **Glossary & map** tab: its terms
|
|
15
|
+
as a list or a mindmap. Teammates limited to some projects now see it too, with the terms their projects use and
|
|
16
|
+
what their projects say of them, never what another project wrote
|
|
17
|
+
([On a team hub](docs/dashboard.md#on-a-team-hub)).
|
|
18
|
+
|
|
6
19
|
## 0.29.1 (2026-10-25)
|
|
7
20
|
|
|
8
21
|
- **The interview, your job goal's final boss:** three questions a day, written from the job description and from
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: interlatch
|
|
3
|
-
Version: 0.29.
|
|
3
|
+
Version: 0.29.3
|
|
4
4
|
Summary: Shared memory for your coding agents: records every session (Claude Code, Codex, Copilot, Bob, Antigravity, OpenCode) locally and keeps what they learned, each lesson linked to the session it came from.
|
|
5
5
|
Project-URL: Homepage, https://interlatch.com
|
|
6
6
|
Project-URL: Documentation, https://interlatch.com/docs/
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
- **Analysis usage on every page:** the status bar shows your Claude plan's session (5hr) and weekly (7 day) usage, as
|
|
2
|
+
Claude Code names them, and what analysis spent today. Click it to see what's left and when each resets, this month's
|
|
3
|
+
and all-time spend, and to set the analysis limits: sessions per run, the budget per call, and a new cap that pauses
|
|
4
|
+
automatic analysis at a percent of your plan limit ([Configuration](docs/configuration.md)).
|
|
@@ -35,6 +35,7 @@ the file. Changes apply on the next sync or worker run. `INTERLATCH_HOME` reloca
|
|
|
35
35
|
| `idle_minutes` | `20` | a session must have ended or been idle this long before it is analyzed |
|
|
36
36
|
| `min_prompts` | `1` | sessions with fewer human prompts are skipped |
|
|
37
37
|
| `max_per_run` / `concurrency` | `6` / `2` | analyses per 15-minute run, and parallel analysis processes |
|
|
38
|
+
| `plan_limit_pct` | `0` | pause automatic analysis while your Claude plan's session (5hr) or weekly (7 day) limit is at or above this percent (Claude Code as the analyzer, with the status-line collector); `0` never pauses. Set it, and the limits above, from the usage chip in the dashboard's status bar |
|
|
38
39
|
| `backfill` | `true` | also analyze sessions recorded before install (newest first) |
|
|
39
40
|
| `chunk_chars` | `150000` | characters of condensed transcript per call; longer sessions are map-reduced |
|
|
40
41
|
| `timeout_seconds` | `900` | wall-clock limit per call |
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
| `idle_minutes` | `20` | 分析されるには、セッションが終了しているか、この時間アイドルである必要があります |
|
|
36
36
|
| `min_prompts` | `1` | 人間のプロンプトがこれより少ないセッションはスキップされます |
|
|
37
37
|
| `max_per_run` / `concurrency` | `6` / `2` | 15 分ごとの実行 1 回あたりの分析数と、並列に動かす分析プロセスの数 |
|
|
38
|
+
| `plan_limit_pct` | `0` | Claude プランのセッション(5 時間)または週間(7 日)の上限がこの割合以上のあいだ、自動分析を止めます(分析エンジンが Claude Code で、ステータスラインの収集があるとき)。`0` は止めません。これと上の上限は、ダッシュボードのステータスバーの使用量から設定できます |
|
|
38
39
|
| `backfill` | `true` | インストール前に記録されたセッションも分析する(新しい順) |
|
|
39
40
|
| `chunk_chars` | `150000` | 1 回の呼び出しに渡す、まとめたトランスクリプトの文字数。これより長いセッションは map-reduce で処理します |
|
|
40
41
|
| `timeout_seconds` | `900` | 呼び出し 1 回あたりの実時間の上限 |
|
|
@@ -95,12 +95,36 @@ def queue_block(conn, cfg: Config, runner: Runner | None = None) -> str | None:
|
|
|
95
95
|
return tr("analysis is off (record only): pick an analyzer in Status › Analysis to analyze sessions")
|
|
96
96
|
if not cfg.analysis.auto:
|
|
97
97
|
return tr("automatic analysis is off (analysis.auto); analyze it from its page or with `interlatch analyze`")
|
|
98
|
+
over = plan_over_limit(conn, cfg)
|
|
99
|
+
if over:
|
|
100
|
+
return tr("your Claude plan's {window} limit is at {pct}%, at or above the {cap}% you set; it resumes after {when}",
|
|
101
|
+
window=tr(WINDOW_LABEL.get(over["window"], over["window"])), pct=round(over["used_pct"]),
|
|
102
|
+
cap=cfg.analysis.plan_limit_pct, when=local_str(over["resets_at"], "%m-%d %H:%M"))
|
|
98
103
|
runner = runner or make_runner(cfg)
|
|
99
104
|
if not runner.available():
|
|
100
105
|
return tr("{reason}, so nothing can be analyzed", reason=runner.unavailable_reason())
|
|
101
106
|
return None
|
|
102
107
|
|
|
103
108
|
|
|
109
|
+
WINDOW_LABEL = {"five_hour": "session (5hr)", "seven_day": "weekly (7 day)", "spend_limit": "spend"} # Claude Code's names
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def plan_over_limit(conn, cfg: Config) -> dict | None:
|
|
113
|
+
"""The Claude plan window (statusline.py) at or above analysis.plan_limit_pct, while Claude Code analyzes: its
|
|
114
|
+
name, used_pct and resets_at. None when the cap is off, another analyzer runs, or no window is that full."""
|
|
115
|
+
cap = cfg.analysis.plan_limit_pct
|
|
116
|
+
if not cap or cap <= 0 or cfg.analysis.backend != "claude":
|
|
117
|
+
return None
|
|
118
|
+
from ..runtime.statusline import plan_usage
|
|
119
|
+
|
|
120
|
+
windows = (plan_usage(conn) or {}).get("limits") or {}
|
|
121
|
+
over = [(name, w) for name, w in windows.items() if name in WINDOW_LABEL and (w.get("used_pct") or 0) >= cap]
|
|
122
|
+
if not over:
|
|
123
|
+
return None
|
|
124
|
+
name, w = max(over, key=lambda x: x[1]["resets_at"]) # the one that frees up last
|
|
125
|
+
return {"window": name, "used_pct": w["used_pct"], "resets_at": w["resets_at"]}
|
|
126
|
+
|
|
127
|
+
|
|
104
128
|
def count_pending(conn, cfg: Config) -> dict:
|
|
105
129
|
"""The analysis queue: `ready` now, `queued` (everything that will be analyzed by itself, ready included),
|
|
106
130
|
`held` (needs a change first), each with a count per reason, and `block` when the whole queue is stopped."""
|
|
@@ -9,7 +9,7 @@ import sqlite3
|
|
|
9
9
|
from collections.abc import Callable
|
|
10
10
|
from datetime import timedelta
|
|
11
11
|
|
|
12
|
-
from ..analysis.queue import PAUSE_KEY, pending_sessions
|
|
12
|
+
from ..analysis.queue import PAUSE_KEY, pending_sessions, plan_over_limit
|
|
13
13
|
from ..analysis.runners.base import LLMError, Runner, UsageLimitError
|
|
14
14
|
from ..analysis.runners.factory import make_runner
|
|
15
15
|
from ..analysis.worker import WorkReport, analyze_many
|
|
@@ -92,7 +92,12 @@ def _run_locked(cfg: Config, conn, report: WorkReport, *, session_ids, max_analy
|
|
|
92
92
|
conn.commit()
|
|
93
93
|
runner = make_runner(cfg)
|
|
94
94
|
paused = kv_get(conn, PAUSE_KEY)
|
|
95
|
-
|
|
95
|
+
# at the plan limit the user set (analysis.plan_limit_pct): runs on their own wait; sessions asked for still run
|
|
96
|
+
capped = None if session_ids or force else plan_over_limit(conn, cfg)
|
|
97
|
+
if capped:
|
|
98
|
+
report.note = (f"Claude plan's {capped['window']} limit at {capped['used_pct']:.0f}% "
|
|
99
|
+
f"(analysis.plan_limit_pct = {cfg.analysis.plan_limit_pct}); analysis skipped")
|
|
100
|
+
if analyze and not capped and (cfg.analysis.auto or session_ids or force):
|
|
96
101
|
if paused and paused > to_iso(utcnow()) and not session_ids:
|
|
97
102
|
report.paused_until = paused
|
|
98
103
|
elif not runner.available():
|
|
@@ -102,9 +107,9 @@ def _run_locked(cfg: Config, conn, report: WorkReport, *, session_ids, max_analy
|
|
|
102
107
|
analyze_many(cfg, ids, runner, report, model=model, progress=progress)
|
|
103
108
|
auto = cfg.synthesis.auto or force
|
|
104
109
|
# the projects and groups whose weekly re-analysis is due: someone turned each on, so they run without [synthesis] auto
|
|
105
|
-
due = (_weekly_due(cfg, conn) if synthesize and not session_ids and runner.available()
|
|
106
|
-
and not (paused and paused > to_iso(utcnow())) else [])
|
|
107
|
-
if synthesize and (auto or due) and runner.available() and not report.paused_until:
|
|
110
|
+
due = (_weekly_due(cfg, conn) if synthesize and not session_ids and not capped and runner.available()
|
|
111
|
+
and not report.paused_until and not (paused and paused > to_iso(utcnow())) else [])
|
|
112
|
+
if synthesize and not capped and (auto or due) and runner.available() and not report.paused_until:
|
|
108
113
|
_synthesize(cfg, conn, runner, report, force=force, auto=auto, also=_weekly_projects(cfg, conn, due),
|
|
109
114
|
progress=progress)
|
|
110
115
|
_glossaries(cfg, conn, runner, report, progress=progress)
|
|
@@ -62,6 +62,9 @@ idle_minutes = 20
|
|
|
62
62
|
min_prompts = 1
|
|
63
63
|
# Max session analyses per worker run (the background job runs every 15 minutes).
|
|
64
64
|
max_per_run = 6
|
|
65
|
+
# Pause automatic analysis while your Claude plan's 5-hour or 7-day limit is at or above this percent (backend
|
|
66
|
+
# "claude", needs `interlatch install --statusline`). 0 = never pause for it.
|
|
67
|
+
plan_limit_pct = 0
|
|
65
68
|
# Parallel analysis processes.
|
|
66
69
|
concurrency = 2
|
|
67
70
|
# Also analyze sessions recorded before Interlatch was installed (newest first, within max_per_run).
|
|
@@ -275,6 +278,7 @@ class AnalysisConfig:
|
|
|
275
278
|
idle_minutes: int = 20
|
|
276
279
|
min_prompts: int = 1
|
|
277
280
|
max_per_run: int = 6
|
|
281
|
+
plan_limit_pct: int = 0 # pause automatic runs at this % of a Claude plan limit; 0 = off
|
|
278
282
|
concurrency: int = 2
|
|
279
283
|
backfill: bool = True
|
|
280
284
|
chunk_chars: int = 150_000
|
|
@@ -156,6 +156,9 @@ JA: dict[str, str] = {
|
|
|
156
156
|
"準備完了:バックグラウンドの処理が次の実行(15 分ごと)で分析します",
|
|
157
157
|
"ready to re-analyze: the session continued after it was analyzed": "再分析の準備完了:分析のあとにセッションが続きました",
|
|
158
158
|
"analysis is paused until {when} (usage limit); it resumes by itself": "使用量の上限のため、分析は {when} まで一時停止しています。自動で再開します",
|
|
159
|
+
"your Claude plan's {window} limit is at {pct}%, at or above the {cap}% you set; it resumes after {when}":
|
|
160
|
+
"Claude プランの{window}の上限が {pct}% で、設定した {cap}% 以上です。{when} 以降に再開します",
|
|
161
|
+
"session (5hr)": "セッション(5 時間)", "weekly (7 day)": "週間(7 日)", "spend": "利用額",
|
|
159
162
|
"automatic analysis is off (analysis.auto); analyze it from its page or with `interlatch analyze`":
|
|
160
163
|
"自動分析がオフです(analysis.auto)。セッションのページか `interlatch analyze` で分析してください",
|
|
161
164
|
"analysis is off (record only): pick an analyzer in Status › Analysis to analyze sessions":
|
|
@@ -178,9 +178,59 @@ def status_small(ctx: Context, limited: bool = False) -> dict:
|
|
|
178
178
|
"hub_url": ctx.cfg.hub_url or None, # set on a computer that sends its sessions to a hub
|
|
179
179
|
"hub_urls": [c.hub_url for c in sending], # and the other hubs it sends to (docs/profiles.md)
|
|
180
180
|
"hub_problem": _hub_problem(sending), # its pushes don't get through: the status bar warns
|
|
181
|
+
"usage": analysis_usage(ctx), # the status bar's usage chip and the limits it sets
|
|
181
182
|
}
|
|
182
183
|
|
|
183
184
|
|
|
185
|
+
def analysis_usage(ctx: Context) -> dict:
|
|
186
|
+
"""What analysis has used (API-equivalent USD today, this month, all time; the Claude plan's windows from the status
|
|
187
|
+
line) and the limits set for it (analysis.max_per_run, max_budget_usd, plan_limit_pct)."""
|
|
188
|
+
from ....analysis.queue import plan_over_limit, queue_block
|
|
189
|
+
from ....runtime.install import statusline_installed
|
|
190
|
+
from ....runtime.statusline import plan_usage
|
|
191
|
+
|
|
192
|
+
a = ctx.cfg.analysis
|
|
193
|
+
day = datetime.now().astimezone().replace(hour=0, minute=0, second=0, microsecond=0)
|
|
194
|
+
today, month = to_iso(day), to_iso(day.replace(day=1))
|
|
195
|
+
row = ctx.conn.execute(
|
|
196
|
+
"SELECT COALESCE(SUM(CASE WHEN started_at >= ? THEN cost_usd END), 0), "
|
|
197
|
+
"COALESCE(SUM(CASE WHEN started_at >= ? THEN cost_usd END), 0), COALESCE(SUM(cost_usd), 0), "
|
|
198
|
+
"SUM(CASE WHEN started_at >= ? THEN 1 ELSE 0 END) FROM analyses", (today, month, today)).fetchone()
|
|
199
|
+
over = plan_over_limit(ctx.conn, ctx.cfg)
|
|
200
|
+
return {"spent": {"today": row[0], "month": row[1], "total": row[2]}, "calls_today": row[3] or 0,
|
|
201
|
+
"plan": plan_usage(ctx.conn), "plan_applies": a.backend == "claude", "over": over,
|
|
202
|
+
"collector": statusline_installed(ctx.cfg), # without it no plan readings ever arrive
|
|
203
|
+
"block": queue_block(ctx.conn, ctx.cfg) if over else None, # why the queue stopped, in the queue's words
|
|
204
|
+
"limits": {"max_per_run": a.max_per_run, "max_budget_usd": a.max_budget_usd, "plan_limit_pct": a.plan_limit_pct}}
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
# what the status bar's usage panel may set, with the bounds a value must be in
|
|
208
|
+
LIMITS = {"max_per_run": (int, 1, 100), "max_budget_usd": (float, 0.1, 100.0), "plan_limit_pct": (int, 0, 100)}
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def action_limits(ctx: Context, body: dict) -> dict:
|
|
212
|
+
"""Save the analysis limits (LIMITS) the status bar's usage panel sets; returns the usage with them."""
|
|
213
|
+
from ....core.config import load_config, set_config_value
|
|
214
|
+
|
|
215
|
+
refused = []
|
|
216
|
+
for key, (kind, lo, hi) in LIMITS.items():
|
|
217
|
+
if key not in body:
|
|
218
|
+
continue
|
|
219
|
+
try:
|
|
220
|
+
v = kind(body[key])
|
|
221
|
+
except (TypeError, ValueError):
|
|
222
|
+
v = None
|
|
223
|
+
if v is None or isinstance(body[key], bool) or not lo <= v <= hi:
|
|
224
|
+
refused.append(key)
|
|
225
|
+
continue
|
|
226
|
+
set_config_value(ctx.cfg, "analysis", key, f"{v:.2f}" if kind is float else str(v))
|
|
227
|
+
ctx.cfg = load_config(ctx.cfg.home)
|
|
228
|
+
out = analysis_usage(ctx)
|
|
229
|
+
if refused:
|
|
230
|
+
out["error"] = tr("not saved: {keys}", keys=", ".join(refused))
|
|
231
|
+
return out
|
|
232
|
+
|
|
233
|
+
|
|
184
234
|
def _sending_to(ctx: Context) -> list:
|
|
185
235
|
"""The configs that send to a hub: Personal's (when it joined one), then each other hub this computer joined."""
|
|
186
236
|
from ....application.profiles import joined
|
|
@@ -478,6 +478,7 @@ POST: list[Route] = [
|
|
|
478
478
|
Route("/api/analysis/backend", ANYONE,
|
|
479
479
|
lambda h, ctx, m, b: h._json(api.settings.action_backend(ctx, str(b.get("backend") or "")))),
|
|
480
480
|
Route("/api/analysis/agent", ANYONE, lambda h, ctx, m, b: h._json(api.settings.action_agent(ctx, _body(b)))),
|
|
481
|
+
Route("/api/analysis/limits", ANYONE, lambda h, ctx, m, b: h._json(api.status.action_limits(ctx, _body(b)))),
|
|
481
482
|
# an API key, and where transcripts are sent
|
|
482
483
|
Route("/api/analysis/provider", OWNER, lambda h, ctx, m, b: h._json(api.settings.action_provider(ctx, _body(b)))),
|
|
483
484
|
Route("/api/analysis/provider/test", OWNER, lambda h, ctx, m, b: h._json(
|
|
@@ -1727,6 +1727,34 @@ table.data tr.picked:hover td { background: color-mix(in srgb, var(--accent) 11%
|
|
|
1727
1727
|
#activity .act-mark.no { color: var(--critical-ink); }
|
|
1728
1728
|
#activity .act-foot { display: flex; justify-content: space-between; align-items: center; gap: 8px; padding-top: 10px; border-top: 1px solid var(--grid); font-size: 12px; }
|
|
1729
1729
|
:root[data-motion="off"] #activity, :root[data-motion="off"] #activity .act-bar i { animation: none; transition: none; } :root[data-motion="off"] #activity .act-bar.indeterminate i { left: 0; width: 100%; opacity: 0.4; }
|
|
1730
|
+
/* Analysis usage: what the status bar's usage chip opens: the plan's windows, analysis spend, and the limits */
|
|
1731
|
+
#usage-panel { position: fixed; left: 12px; bottom: 38px; z-index: 62; width: min(380px, calc(100vw - 24px)); max-height: min(75vh, 600px); overflow-y: auto;
|
|
1732
|
+
padding: 12px 14px; border-radius: 6px; background: var(--glass-strong); color: var(--ink); font-size: 13px;
|
|
1733
|
+
box-shadow: var(--glass-shadow), 0 10px 32px rgba(0, 0, 0, 0.16), inset 0 0 0 0.5px var(--glass-rim); animation: upd-in 0.18s ease-out; }
|
|
1734
|
+
#usage-panel .act-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; font-size: 14px; }
|
|
1735
|
+
#usage-panel .un-close { border: 0; background: transparent; color: var(--muted); font-size: 17px; line-height: 1; padding: 2px 5px; border-radius: 6px; cursor: pointer; }
|
|
1736
|
+
#usage-panel .un-close:hover { background: var(--hover); color: var(--ink); }
|
|
1737
|
+
#usage-panel .subhead { margin: 12px 0 6px; }
|
|
1738
|
+
#usage-panel .warn-line { margin: 6px 0 0; font-size: 12.5px; }
|
|
1739
|
+
#usage-panel .us-wins { display: grid; gap: 10px; }
|
|
1740
|
+
#usage-panel .us-top { display: flex; justify-content: space-between; gap: 10px; font-variant-numeric: tabular-nums; }
|
|
1741
|
+
#usage-panel .us-bar { position: relative; height: 6px; margin-top: 6px; border-radius: 3px; background: var(--surface-3); }
|
|
1742
|
+
#usage-panel .us-bar i { position: absolute; inset: 0 auto 0 0; border-radius: 3px; background: var(--accent); }
|
|
1743
|
+
#usage-panel .us-bar.over i { background: var(--warning); }
|
|
1744
|
+
#usage-panel .us-bar u { position: absolute; top: -3px; bottom: -3px; width: 2px; margin-left: -1px; border-radius: 1px; background: var(--ink-2); }
|
|
1745
|
+
#usage-panel .us-note { font-size: 12px; }
|
|
1746
|
+
#usage-panel .us-win .us-note { margin-top: 4px; }
|
|
1747
|
+
#usage-panel .us-facts { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
|
|
1748
|
+
#usage-panel .us-facts .fact { display: grid; gap: 1px; }
|
|
1749
|
+
#usage-panel .us-facts b { font-size: 15px; font-variant-numeric: tabular-nums; }
|
|
1750
|
+
#usage-panel .us-facts span { font-size: 11.5px; color: var(--muted); }
|
|
1751
|
+
#usage-panel .us-form { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 12px; align-items: start; }
|
|
1752
|
+
#usage-panel .us-form label { display: grid; gap: 3px; font-size: 12px; color: var(--ink-2); }
|
|
1753
|
+
#usage-panel .us-form label:nth-child(3) { grid-column: 1 / -1; }
|
|
1754
|
+
#usage-panel .us-form small { font-size: 11px; }
|
|
1755
|
+
#usage-panel .us-form .input { width: 100%; }
|
|
1756
|
+
#usage-panel .us-save { grid-column: 1 / -1; display: flex; justify-content: flex-end; }
|
|
1757
|
+
:root[data-motion="off"] #usage-panel { animation: none; }
|
|
1730
1758
|
|
|
1731
1759
|
/* Export: a small menu of formats under (or, in the selection bar, above) its button */
|
|
1732
1760
|
details.menu { position: relative; }
|
|
@@ -9117,6 +9117,7 @@ async function pollStatus() {
|
|
|
9117
9117
|
: st.last_sync ? t("Synced {ago}", { ago: ago(st.last_sync) }) : t("Not synced yet");
|
|
9118
9118
|
$("#status-version").textContent = st.version ? `Interlatch ${st.version}` : "";
|
|
9119
9119
|
showHubProblem(st.hub_problem);
|
|
9120
|
+
showUsage(st);
|
|
9120
9121
|
showUpdate(st.update, st.version);
|
|
9121
9122
|
pollUnseen();
|
|
9122
9123
|
pollNews();
|
|
@@ -9185,6 +9186,7 @@ function toggleActivity(force) {
|
|
|
9185
9186
|
const open = force ?? box.hidden;
|
|
9186
9187
|
box.hidden = !open;
|
|
9187
9188
|
$("#status-pill").setAttribute("aria-expanded", String(open));
|
|
9189
|
+
if (open && !$("#usage-panel").hidden) toggleUsage(false);
|
|
9188
9190
|
if (open) { if (lastStatus) drawActivity(lastStatus); pollStatus(); }
|
|
9189
9191
|
}
|
|
9190
9192
|
function drawActivity(st) {
|
|
@@ -9241,6 +9243,86 @@ function showHubProblem(pb) {
|
|
|
9241
9243
|
chip.dataset.page = `#/hub?name=${encodeURIComponent(pb.profile || "personal")}`;
|
|
9242
9244
|
chip.title = `${hubProblemTitle(pb)} · ${t("since {time}", { time: fmtDT(pb.since) })}`;
|
|
9243
9245
|
}
|
|
9246
|
+
// Analysis usage on every page: a chip in the status bar (the Claude plan's windows, what analysis spent today) that
|
|
9247
|
+
// opens a panel with the detail and the limits analysis runs under (analysis_usage, action_limits)
|
|
9248
|
+
// named as Claude Code's own Account & usage panel names them
|
|
9249
|
+
const PLAN_SHORT = { five_hour: t("Session"), seven_day: t("Weekly"), spend_limit: t("spend") };
|
|
9250
|
+
const PLAN_NAME = { five_hour: t("Session (5hr)"), seven_day: t("Weekly (7 day)"), spend_limit: t("Spend limit") };
|
|
9251
|
+
const PLAN_CAPS = [0, 50, 60, 70, 80, 90, 95];
|
|
9252
|
+
function showUsage(st) {
|
|
9253
|
+
const chip = $("#status-usage"), u = st.usage;
|
|
9254
|
+
chip.hidden = !u || st.limited;
|
|
9255
|
+
if (chip.hidden) return;
|
|
9256
|
+
const cap = u.plan_applies ? u.limits.plan_limit_pct : 0;
|
|
9257
|
+
const wins = Object.entries(u.plan?.limits || {}).map(([k, v]) => `${PLAN_SHORT[k] || k} ${Math.round(v.used_pct)}%`);
|
|
9258
|
+
chip.className = u.over ? "warn" : "";
|
|
9259
|
+
if (!wins.length) wins.push(u.collector ? t("plan usage: waiting for Claude Code") : t("plan usage: not set up"));
|
|
9260
|
+
chip.replaceChildren(h("span", { class: "dot" }), [...wins, cap && u.plan?.limits && Object.keys(u.plan.limits).length ? t("pauses at {pct}%", { pct: cap }) : null,
|
|
9261
|
+
t("{cost} today", { cost: fmtCost(u.spent.today) })].filter(Boolean).join(" · "));
|
|
9262
|
+
chip.title = u.block || t("Analysis usage and limits: click to see and change them");
|
|
9263
|
+
}
|
|
9264
|
+
function toggleUsage(force) {
|
|
9265
|
+
const box = $("#usage-panel");
|
|
9266
|
+
const open = force ?? box.hidden;
|
|
9267
|
+
box.hidden = !open;
|
|
9268
|
+
$("#status-usage").setAttribute("aria-expanded", String(open));
|
|
9269
|
+
if (open) { toggleActivity(false); if (lastStatus?.usage) drawUsage(lastStatus.usage); }
|
|
9270
|
+
}
|
|
9271
|
+
// drawn when it opens and after a save, not on every poll, so a value being typed stays
|
|
9272
|
+
function drawUsage(u) {
|
|
9273
|
+
const box = $("#usage-panel"), admin = canAdmin(), lim = u.limits;
|
|
9274
|
+
const cap = u.plan_applies ? lim.plan_limit_pct : 0;
|
|
9275
|
+
const win = ([k, v]) => h("div", { class: "us-win" },
|
|
9276
|
+
h("div", { class: "us-top" }, h("b", null, PLAN_NAME[k] || k), h("span", null, `${Math.round(v.used_pct)}%`)),
|
|
9277
|
+
h("div", { class: `us-bar${cap && v.used_pct >= cap ? " over" : ""}`, role: "meter", "aria-label": PLAN_NAME[k] || k,
|
|
9278
|
+
"aria-valuemin": "0", "aria-valuemax": "100", "aria-valuenow": String(Math.round(v.used_pct)) },
|
|
9279
|
+
h("i", { style: { width: `${Math.min(100, Math.max(1, v.used_pct))}%` } }),
|
|
9280
|
+
cap ? h("u", { style: { left: `${cap}%` }, title: t("Analysis pauses at {pct}%", { pct: cap }) }) : null),
|
|
9281
|
+
h("div", { class: "muted us-note", title: fmtDT(v.resets_at) }, t("{pct}% left · resets {when}",
|
|
9282
|
+
{ pct: Math.max(0, 100 - Math.round(v.used_pct)), when: untilText(v.resets_at) })));
|
|
9283
|
+
const wins = Object.entries(u.plan?.limits || {});
|
|
9284
|
+
const plan = wins.length ? [...wins.map(win), h("div", { class: "muted us-note" }, [t("as of {ago}", { ago: ago(u.plan.as_of) }),
|
|
9285
|
+
!u.plan_applies ? t("Analysis isn't using Claude Code now, so these don't limit it") : null].filter(Boolean).join(" · "))]
|
|
9286
|
+
: h("div", { class: "muted us-note" }, u.collector
|
|
9287
|
+
? t("Recorded from Claude Code's status line: the numbers come with your next Claude Code session in a terminal and the sync after it (Pro and Max plans).")
|
|
9288
|
+
: tx("Not set up: run {command} so Claude Code's status line records them (Pro and Max plans). Until then the pause at plan limit can't act.",
|
|
9289
|
+
{ command: h("code", null, "interlatch install --statusline") }));
|
|
9290
|
+
const fact = (v, label) => h("div", { class: "fact" }, h("b", null, fmtCost(v)), h("span", null, label));
|
|
9291
|
+
const num = (name, label, attrs, hint) => h("label", null, h("span", null, label),
|
|
9292
|
+
h("input", { class: "input", type: "number", name, value: lim[name], disabled: !admin, required: true, ...attrs }), hint ? h("small", { class: "muted" }, hint) : null);
|
|
9293
|
+
const caps = PLAN_CAPS.includes(lim.plan_limit_pct) ? PLAN_CAPS : [...PLAN_CAPS, lim.plan_limit_pct].sort((a, b) => a - b);
|
|
9294
|
+
const form = h("form", { class: "us-form", onsubmit: async (e) => {
|
|
9295
|
+
e.preventDefault();
|
|
9296
|
+
const f = e.currentTarget, btn = f.querySelector("button[type=submit]");
|
|
9297
|
+
btn.disabled = true;
|
|
9298
|
+
const r = await post("/api/analysis/limits", { max_per_run: +f.max_per_run.value, max_budget_usd: +f.max_budget_usd.value,
|
|
9299
|
+
plan_limit_pct: +f.plan_limit_pct.value }).catch((err) => ({ error: err.message }));
|
|
9300
|
+
btn.disabled = false;
|
|
9301
|
+
if (r.error) { toast(r.error, 6000); return; }
|
|
9302
|
+
toast(t("Analysis limits saved."));
|
|
9303
|
+
lastStatus = { ...lastStatus, usage: r };
|
|
9304
|
+
drawUsage(r);
|
|
9305
|
+
pollStatus(); // the chip and the queue's reason follow the new limits
|
|
9306
|
+
} },
|
|
9307
|
+
num("max_per_run", t("Sessions per run"), { min: 1, max: 100, step: 1 }, t("every 15 minutes")),
|
|
9308
|
+
num("max_budget_usd", t("Budget per call (USD)"), { min: 0.1, max: 100, step: 0.1 }, t("API-equivalent; Claude Code and Bob")),
|
|
9309
|
+
h("label", null, h("span", null, t("Pause at plan limit")),
|
|
9310
|
+
h("select", { class: "input", name: "plan_limit_pct", disabled: !admin },
|
|
9311
|
+
caps.map((c) => h("option", { value: c, selected: c === lim.plan_limit_pct }, c ? `${c}%` : t("Never")))),
|
|
9312
|
+
h("small", { class: "muted" }, t("Session or weekly, while Claude Code analyzes"))),
|
|
9313
|
+
h("div", { class: "us-save" }, h("button", { class: "btn small primary", type: "submit", disabled: !admin }, t("Save"))));
|
|
9314
|
+
box.replaceChildren(...[
|
|
9315
|
+
h("div", { class: "act-head" }, h("b", null, t("Analysis usage")),
|
|
9316
|
+
h("button", { class: "un-close", type: "button", "aria-label": t("Close"), onclick: () => toggleUsage(false) }, "×")),
|
|
9317
|
+
u.block ? h("div", { class: "warn-line" }, icon("pause"), " ", LANG === "en" ? `${u.block[0].toUpperCase()}${u.block.slice(1)}.` : `${u.block}。`) : null,
|
|
9318
|
+
h("div", { class: "subhead" }, t("Claude plan")), h("div", { class: "us-wins" }, plan),
|
|
9319
|
+
h("div", { class: "subhead" }, t("Spent on analysis")),
|
|
9320
|
+
h("div", { class: "us-facts", title: t("API-equivalent: what the tokens would cost at list prices") },
|
|
9321
|
+
fact(u.spent.today, t("today")), fact(u.spent.month, t("this month")), fact(u.spent.total, t("all time"))),
|
|
9322
|
+
h("div", { class: "subhead" }, t("Limits")), form,
|
|
9323
|
+
admin ? null : h("div", { class: "muted us-note" }, t("Only an admin can change these.")),
|
|
9324
|
+
].filter(Boolean));
|
|
9325
|
+
}
|
|
9244
9326
|
// an update on offer: a chip in the status bar, a dot on Settings, and once per update a notification card
|
|
9245
9327
|
function showUpdate(u, version) {
|
|
9246
9328
|
const upd = $("#status-update");
|
|
@@ -9419,6 +9501,12 @@ document.addEventListener("mousedown", (e) => { if (!$("#activity").hidden && !e
|
|
|
9419
9501
|
document.addEventListener("keydown", (e) => { if (e.key === "Escape" && !$("#activity").hidden) toggleActivity(false); });
|
|
9420
9502
|
$("#status-update").addEventListener("click", () => go("#/status?focus=updates"));
|
|
9421
9503
|
$("#status-hub-problem").addEventListener("click", (e) => go(e.currentTarget.dataset.page || "#/devices"));
|
|
9504
|
+
$("#status-usage").addEventListener("click", () => toggleUsage());
|
|
9505
|
+
$("#status-usage").setAttribute("aria-haspopup", "dialog");
|
|
9506
|
+
$("#status-usage").setAttribute("aria-expanded", "false");
|
|
9507
|
+
$("#usage-panel").setAttribute("aria-label", t("Analysis usage"));
|
|
9508
|
+
document.addEventListener("mousedown", (e) => { if (!$("#usage-panel").hidden && !e.target.closest("#usage-panel, #status-usage")) toggleUsage(false); });
|
|
9509
|
+
document.addEventListener("keydown", (e) => { if (e.key === "Escape" && !$("#usage-panel").hidden) toggleUsage(false); });
|
|
9422
9510
|
$("#status-queue").addEventListener("click", openQueueDialog);
|
|
9423
9511
|
$("#status-queue").setAttribute("aria-haspopup", "dialog");
|
|
9424
9512
|
$("#status-queue").setAttribute("aria-expanded", "false");
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
<span id="status-hub" hidden></span>
|
|
69
69
|
<button type="button" id="status-pill" title="Background work"></button>
|
|
70
70
|
<button type="button" id="status-queue" hidden></button>
|
|
71
|
+
<button type="button" id="status-usage" hidden></button>
|
|
71
72
|
</div>
|
|
72
73
|
<div class="st-right">
|
|
73
74
|
<span id="status-sync"></span>
|
|
@@ -85,6 +86,7 @@
|
|
|
85
86
|
<div id="toast" role="status" aria-live="polite" hidden></div>
|
|
86
87
|
<div id="update-note" role="status" aria-live="polite" hidden></div>
|
|
87
88
|
<div id="activity" role="dialog" aria-label="Activity" hidden></div>
|
|
89
|
+
<div id="usage-panel" role="dialog" aria-label="Analysis usage" hidden></div>
|
|
88
90
|
<script src="rough.js"></script>
|
|
89
91
|
<script src="ja.js"></script>
|
|
90
92
|
<script src="i18n.js"></script>
|
|
@@ -73,6 +73,36 @@ window.INTERLATCH_JA = {
|
|
|
73
73
|
"{limit} limit {pct}% (resets {when})": "{limit}の上限 {pct}%({when} にリセット)",
|
|
74
74
|
"as of {ago}": "取得:{ago}",
|
|
75
75
|
"{limit} limit used": "{limit}の上限の使用量",
|
|
76
|
+
// Analysis usage: the status bar's chip and panel
|
|
77
|
+
"Weekly": "週間",
|
|
78
|
+
"Session (5hr)": "セッション(5 時間)",
|
|
79
|
+
"Weekly (7 day)": "週間(7 日)",
|
|
80
|
+
"Spend limit": "利用額の上限",
|
|
81
|
+
"{pct}% left · resets {when}": "残り {pct}% · {when}にリセット",
|
|
82
|
+
"{cost} today": "今日 {cost}",
|
|
83
|
+
"pauses at {pct}%": "{pct}% で停止",
|
|
84
|
+
"Analysis usage and limits: click to see and change them": "分析の使用量と上限:クリックで確認・変更",
|
|
85
|
+
"Analysis pauses at {pct}%": "{pct}% で分析を一時停止",
|
|
86
|
+
"Analysis isn't using Claude Code now, so these don't limit it": "いまの分析は Claude Code を使っていないため、これらの上限はかかりません",
|
|
87
|
+
"plan usage: waiting for Claude Code": "プランの使用量:Claude Code を待っています",
|
|
88
|
+
"plan usage: not set up": "プランの使用量:未設定",
|
|
89
|
+
"Recorded from Claude Code's status line: the numbers come with your next Claude Code session in a terminal and the sync after it (Pro and Max plans).": "Claude Code のステータスラインから記録します。次にターミナルで Claude Code を使い、そのあと同期すると表示されます(Pro と Max プラン)。",
|
|
90
|
+
"Not set up: run {command} so Claude Code's status line records them (Pro and Max plans). Until then the pause at plan limit can't act.": "未設定です。{command} を実行すると、Claude Code のステータスラインが記録します(Pro と Max プラン)。それまでは「プランの上限で一時停止」は働きません。",
|
|
91
|
+
"Analysis limits saved.": "分析の上限を保存しました。",
|
|
92
|
+
"Sessions per run": "1 回の実行のセッション数",
|
|
93
|
+
"every 15 minutes": "15 分ごと",
|
|
94
|
+
"Budget per call (USD)": "1 回の呼び出しの予算(USD)",
|
|
95
|
+
"API-equivalent; Claude Code and Bob": "API 換算。Claude Code と Bob",
|
|
96
|
+
"Pause at plan limit": "プランの上限で一時停止",
|
|
97
|
+
"Never": "しない",
|
|
98
|
+
"Session or weekly, while Claude Code analyzes": "セッションまたは週間。Claude Code で分析しているとき",
|
|
99
|
+
"Analysis usage": "分析の使用量",
|
|
100
|
+
"Claude plan": "Claude プラン",
|
|
101
|
+
"Spent on analysis": "分析に使った額",
|
|
102
|
+
"today": "今日",
|
|
103
|
+
"this month": "今月",
|
|
104
|
+
"Limits": "上限",
|
|
105
|
+
"Only an admin can change these.": "変更できるのは管理者だけです。",
|
|
76
106
|
"How far your plan limits moved while this session ran (includes anything else using the same account then)": "このセッションの実行中にプランの上限がどれだけ進んだか(同じ時間に同じアカウントを使ったものも含みます)",
|
|
77
107
|
"ready now": "すぐに分析",
|
|
78
108
|
"still active": "まだ作業中",
|
|
@@ -187,3 +187,63 @@ def test_a_spoke_that_shares_knowledge_analyzes_here(synced):
|
|
|
187
187
|
assert st["hub_url"] and st["analysis"]["on_hub"] is on_hub
|
|
188
188
|
assert api.status.analysis_queue(app.context())["on_hub"] is on_hub
|
|
189
189
|
assert api.status.status_small(App(cfg).context())["analysis"]["on_hub"] is False
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _plan(conn, five_hour, seven_day=10.0):
|
|
193
|
+
import json
|
|
194
|
+
|
|
195
|
+
later = to_iso(utcnow() + timedelta(hours=2))
|
|
196
|
+
kv_set(conn, "plan_usage_latest", json.dumps({"as_of": to_iso(utcnow()), "limits": {
|
|
197
|
+
"five_hour": {"used_pct": five_hour, "resets_at": later},
|
|
198
|
+
"seven_day": {"used_pct": seven_day, "resets_at": to_iso(utcnow() + timedelta(days=3))}}}))
|
|
199
|
+
conn.commit()
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def test_the_plan_limit_the_user_set_stops_automatic_runs(synced):
|
|
203
|
+
"""analysis.plan_limit_pct: at or above it, the queue says why and a background run analyzes nothing; a session
|
|
204
|
+
asked for still runs, and the cap means nothing while another analyzer runs or when it is 0."""
|
|
205
|
+
from interlatch.analysis.queue import plan_over_limit
|
|
206
|
+
from interlatch.application.workflows import run_worker
|
|
207
|
+
|
|
208
|
+
conn, cfg = synced["conn"], synced["cfg"]
|
|
209
|
+
conn.execute("UPDATE sessions SET analysis_status = 'pending', analysis_attempts = 0, ended_flag = 1")
|
|
210
|
+
_plan(conn, five_hour=85.0)
|
|
211
|
+
capped = replace(cfg, analysis=replace(cfg.analysis, plan_limit_pct=80))
|
|
212
|
+
assert plan_over_limit(conn, capped)["window"] == "five_hour"
|
|
213
|
+
assert "session (5hr) limit is at 85%, at or above the 80% you set" in count_pending(conn, capped)["block"]
|
|
214
|
+
assert count_pending(conn, replace(capped, analysis=replace(capped.analysis, plan_limit_pct=90)))["block"] is None
|
|
215
|
+
assert count_pending(conn, cfg)["block"] is None # 0: off
|
|
216
|
+
assert plan_over_limit(conn, replace(capped, analysis=replace(capped.analysis, backend="codex"))) is None
|
|
217
|
+
|
|
218
|
+
report = run_worker(capped, synthesize=False)
|
|
219
|
+
assert not report.analyzed and "plan_limit_pct = 80" in report.note
|
|
220
|
+
assert conn.execute("SELECT analysis_status FROM sessions WHERE id = ?", (SID,)).fetchone()[0] == "pending"
|
|
221
|
+
report = run_worker(capped, session_ids=[SID], synthesize=False)
|
|
222
|
+
assert report.analyzed
|
|
223
|
+
assert conn.execute("SELECT analysis_status FROM sessions WHERE id = ?", (SID,)).fetchone()[0] == "done"
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def test_the_status_bar_shows_usage_and_saves_the_limits(synced):
|
|
227
|
+
from interlatch.core.config import load_config
|
|
228
|
+
from interlatch.interfaces.web.app import App
|
|
229
|
+
|
|
230
|
+
conn, cfg = synced["conn"], synced["cfg"]
|
|
231
|
+
_plan(conn, five_hour=42.0)
|
|
232
|
+
conn.execute("INSERT INTO analyses(kind, target, started_at, cost_usd) VALUES ('session', 'x', ?, 0.5), "
|
|
233
|
+
"('session', 'y', '2020-01-01T00:00:00Z', 2.0)", (to_iso(utcnow()),))
|
|
234
|
+
conn.commit()
|
|
235
|
+
ctx = App(cfg).context()
|
|
236
|
+
u = api.status.status_small(ctx)["usage"]
|
|
237
|
+
assert u["spent"]["today"] == 0.5 and u["spent"]["total"] >= 2.5 and u["calls_today"] >= 1
|
|
238
|
+
assert u["plan"]["limits"]["five_hour"]["used_pct"] == 42.0 and u["over"] is None and u["collector"] is False
|
|
239
|
+
assert "usage" not in api.status.status_small(ctx, limited=True) # someone the hub limits to projects
|
|
240
|
+
|
|
241
|
+
r = api.status.action_limits(ctx, {"max_per_run": 3, "max_budget_usd": 1.5, "plan_limit_pct": 40})
|
|
242
|
+
assert r["limits"] == {"max_per_run": 3, "max_budget_usd": 1.5, "plan_limit_pct": 40} and "error" not in r
|
|
243
|
+
assert r["over"]["window"] == "five_hour" and "at or above the 40% you set" in r["block"]
|
|
244
|
+
saved = load_config(cfg.home).analysis
|
|
245
|
+
assert (saved.max_per_run, saved.max_budget_usd, saved.plan_limit_pct) == (3, 1.5, 40)
|
|
246
|
+
|
|
247
|
+
r = api.status.action_limits(ctx, {"max_per_run": 0, "max_budget_usd": "lots", "plan_limit_pct": True})
|
|
248
|
+
assert r["error"] == "not saved: max_per_run, max_budget_usd, plan_limit_pct"
|
|
249
|
+
assert r["limits"] == {"max_per_run": 3, "max_budget_usd": 1.5, "plan_limit_pct": 40}
|
|
@@ -216,6 +216,7 @@ ROUTES: dict[tuple[str, str], Access] = {
|
|
|
216
216
|
("POST", "/api/update"): POST_ADMIN,
|
|
217
217
|
("POST", "/api/analysis/backend"): POST_ADMIN,
|
|
218
218
|
("POST", "/api/analysis/agent"): POST_ADMIN,
|
|
219
|
+
("POST", "/api/analysis/limits"): POST_ADMIN,
|
|
219
220
|
("POST", "/api/analysis/provider"): POST_ADMIN,
|
|
220
221
|
("POST", "/api/analysis/provider/test"): POST_ADMIN,
|
|
221
222
|
("POST", "/api/analysis/provider/models"): POST_ADMIN,
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
- **A project's glossary and mindmap on a team hub:** a project's page there has a **Glossary & map** tab: its terms
|
|
2
|
-
as a list or a mindmap. Teammates limited to some projects now see it too, with the terms their projects use and
|
|
3
|
-
what their projects say of them, never what another project wrote
|
|
4
|
-
([On a team hub](docs/dashboard.md#on-a-team-hub)).
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
- **A project's page on a team hub:** the team's knowledge leads. Each knowledge base entry and lesson names whose
|
|
2
|
-
sessions taught it, lessons two people found separately sit side by side, **Since your last visit** lists new and
|
|
3
|
-
replaced lessons, **Start here** greets someone new to the project, **People** shows who has worked on what (never
|
|
4
|
-
a count per person), and **Who's working on it** draws each person's sessions over eight weeks. Tokens and cost
|
|
5
|
-
move to an admin-only Usage tab, and the Systems map is no longer offered where it would be empty or refused
|
|
6
|
-
([On a team hub](docs/dashboard.md#on-a-team-hub)).
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|