solokit 0.1.1__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.
- solokit/__init__.py +10 -0
- solokit/__version__.py +3 -0
- solokit/cli.py +374 -0
- solokit/core/__init__.py +1 -0
- solokit/core/cache.py +102 -0
- solokit/core/command_runner.py +278 -0
- solokit/core/config.py +453 -0
- solokit/core/config_validator.py +204 -0
- solokit/core/constants.py +291 -0
- solokit/core/error_formatter.py +279 -0
- solokit/core/error_handlers.py +346 -0
- solokit/core/exceptions.py +1567 -0
- solokit/core/file_ops.py +309 -0
- solokit/core/logging_config.py +166 -0
- solokit/core/output.py +99 -0
- solokit/core/performance.py +57 -0
- solokit/core/protocols.py +141 -0
- solokit/core/types.py +312 -0
- solokit/deployment/__init__.py +1 -0
- solokit/deployment/executor.py +411 -0
- solokit/git/__init__.py +1 -0
- solokit/git/integration.py +619 -0
- solokit/init/__init__.py +41 -0
- solokit/init/claude_commands_installer.py +87 -0
- solokit/init/dependency_installer.py +313 -0
- solokit/init/docs_structure.py +90 -0
- solokit/init/env_generator.py +160 -0
- solokit/init/environment_validator.py +334 -0
- solokit/init/git_hooks_installer.py +71 -0
- solokit/init/git_setup.py +188 -0
- solokit/init/gitignore_updater.py +195 -0
- solokit/init/initial_commit.py +145 -0
- solokit/init/initial_scans.py +109 -0
- solokit/init/orchestrator.py +246 -0
- solokit/init/readme_generator.py +207 -0
- solokit/init/session_structure.py +239 -0
- solokit/init/template_installer.py +424 -0
- solokit/learning/__init__.py +1 -0
- solokit/learning/archiver.py +115 -0
- solokit/learning/categorizer.py +126 -0
- solokit/learning/curator.py +428 -0
- solokit/learning/extractor.py +352 -0
- solokit/learning/reporter.py +351 -0
- solokit/learning/repository.py +254 -0
- solokit/learning/similarity.py +342 -0
- solokit/learning/validator.py +144 -0
- solokit/project/__init__.py +1 -0
- solokit/project/init.py +1162 -0
- solokit/project/stack.py +436 -0
- solokit/project/sync_plugin.py +438 -0
- solokit/project/tree.py +375 -0
- solokit/quality/__init__.py +1 -0
- solokit/quality/api_validator.py +424 -0
- solokit/quality/checkers/__init__.py +25 -0
- solokit/quality/checkers/base.py +114 -0
- solokit/quality/checkers/context7.py +221 -0
- solokit/quality/checkers/custom.py +162 -0
- solokit/quality/checkers/deployment.py +323 -0
- solokit/quality/checkers/documentation.py +179 -0
- solokit/quality/checkers/formatting.py +161 -0
- solokit/quality/checkers/integration.py +394 -0
- solokit/quality/checkers/linting.py +159 -0
- solokit/quality/checkers/security.py +261 -0
- solokit/quality/checkers/spec_completeness.py +127 -0
- solokit/quality/checkers/tests.py +184 -0
- solokit/quality/env_validator.py +306 -0
- solokit/quality/gates.py +655 -0
- solokit/quality/reporters/__init__.py +10 -0
- solokit/quality/reporters/base.py +25 -0
- solokit/quality/reporters/console.py +98 -0
- solokit/quality/reporters/json_reporter.py +34 -0
- solokit/quality/results.py +98 -0
- solokit/session/__init__.py +1 -0
- solokit/session/briefing/__init__.py +245 -0
- solokit/session/briefing/documentation_loader.py +53 -0
- solokit/session/briefing/formatter.py +476 -0
- solokit/session/briefing/git_context.py +282 -0
- solokit/session/briefing/learning_loader.py +212 -0
- solokit/session/briefing/milestone_builder.py +78 -0
- solokit/session/briefing/orchestrator.py +137 -0
- solokit/session/briefing/stack_detector.py +51 -0
- solokit/session/briefing/tree_generator.py +52 -0
- solokit/session/briefing/work_item_loader.py +209 -0
- solokit/session/briefing.py +353 -0
- solokit/session/complete.py +1188 -0
- solokit/session/status.py +246 -0
- solokit/session/validate.py +452 -0
- solokit/templates/.claude/commands/end.md +109 -0
- solokit/templates/.claude/commands/init.md +159 -0
- solokit/templates/.claude/commands/learn-curate.md +88 -0
- solokit/templates/.claude/commands/learn-search.md +62 -0
- solokit/templates/.claude/commands/learn-show.md +69 -0
- solokit/templates/.claude/commands/learn.md +136 -0
- solokit/templates/.claude/commands/start.md +114 -0
- solokit/templates/.claude/commands/status.md +22 -0
- solokit/templates/.claude/commands/validate.md +27 -0
- solokit/templates/.claude/commands/work-delete.md +119 -0
- solokit/templates/.claude/commands/work-graph.md +139 -0
- solokit/templates/.claude/commands/work-list.md +26 -0
- solokit/templates/.claude/commands/work-new.md +114 -0
- solokit/templates/.claude/commands/work-next.md +25 -0
- solokit/templates/.claude/commands/work-show.md +24 -0
- solokit/templates/.claude/commands/work-update.md +141 -0
- solokit/templates/CHANGELOG.md +17 -0
- solokit/templates/WORK_ITEM_TYPES.md +141 -0
- solokit/templates/__init__.py +1 -0
- solokit/templates/bug_spec.md +217 -0
- solokit/templates/config.schema.json +150 -0
- solokit/templates/dashboard_refine/base/.gitignore +36 -0
- solokit/templates/dashboard_refine/base/app/(dashboard)/layout.tsx +22 -0
- solokit/templates/dashboard_refine/base/app/(dashboard)/page.tsx +68 -0
- solokit/templates/dashboard_refine/base/app/(dashboard)/users/page.tsx +77 -0
- solokit/templates/dashboard_refine/base/app/globals.css +60 -0
- solokit/templates/dashboard_refine/base/app/layout.tsx +23 -0
- solokit/templates/dashboard_refine/base/app/page.tsx +9 -0
- solokit/templates/dashboard_refine/base/components/client-refine-wrapper.tsx +21 -0
- solokit/templates/dashboard_refine/base/components/layout/header.tsx +44 -0
- solokit/templates/dashboard_refine/base/components/layout/sidebar.tsx +82 -0
- solokit/templates/dashboard_refine/base/components/ui/button.tsx +53 -0
- solokit/templates/dashboard_refine/base/components/ui/card.tsx +78 -0
- solokit/templates/dashboard_refine/base/components/ui/table.tsx +116 -0
- solokit/templates/dashboard_refine/base/components.json +16 -0
- solokit/templates/dashboard_refine/base/lib/refine.tsx +65 -0
- solokit/templates/dashboard_refine/base/lib/utils.ts +13 -0
- solokit/templates/dashboard_refine/base/next.config.ts +10 -0
- solokit/templates/dashboard_refine/base/package.json.template +40 -0
- solokit/templates/dashboard_refine/base/postcss.config.mjs +8 -0
- solokit/templates/dashboard_refine/base/providers/refine-provider.tsx +26 -0
- solokit/templates/dashboard_refine/base/tailwind.config.ts +57 -0
- solokit/templates/dashboard_refine/base/tsconfig.json +27 -0
- solokit/templates/dashboard_refine/docker/Dockerfile +57 -0
- solokit/templates/dashboard_refine/docker/docker-compose.prod.yml +31 -0
- solokit/templates/dashboard_refine/docker/docker-compose.yml +21 -0
- solokit/templates/dashboard_refine/tier-1-essential/.eslintrc.json +7 -0
- solokit/templates/dashboard_refine/tier-1-essential/jest.config.ts +17 -0
- solokit/templates/dashboard_refine/tier-1-essential/jest.setup.ts +1 -0
- solokit/templates/dashboard_refine/tier-1-essential/package.json.tier1.template +57 -0
- solokit/templates/dashboard_refine/tier-1-essential/tests/setup.ts +26 -0
- solokit/templates/dashboard_refine/tier-1-essential/tests/unit/example.test.tsx +73 -0
- solokit/templates/dashboard_refine/tier-2-standard/package.json.tier2.template +62 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/eslint.config.mjs +22 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/package.json.tier3.template +79 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/playwright.config.ts +66 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/stryker.conf.json +38 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/tests/e2e/dashboard.spec.ts +88 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/tests/e2e/user-management.spec.ts +102 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/tests/integration/dashboard.test.tsx +90 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/type-coverage.json +16 -0
- solokit/templates/dashboard_refine/tier-4-production/instrumentation.ts +9 -0
- solokit/templates/dashboard_refine/tier-4-production/k6/dashboard-load-test.js +70 -0
- solokit/templates/dashboard_refine/tier-4-production/next.config.ts +46 -0
- solokit/templates/dashboard_refine/tier-4-production/package.json.tier4.template +89 -0
- solokit/templates/dashboard_refine/tier-4-production/sentry.client.config.ts +26 -0
- solokit/templates/dashboard_refine/tier-4-production/sentry.edge.config.ts +11 -0
- solokit/templates/dashboard_refine/tier-4-production/sentry.server.config.ts +11 -0
- solokit/templates/deployment_spec.md +500 -0
- solokit/templates/feature_spec.md +248 -0
- solokit/templates/fullstack_nextjs/base/.gitignore +36 -0
- solokit/templates/fullstack_nextjs/base/app/api/example/route.ts +65 -0
- solokit/templates/fullstack_nextjs/base/app/globals.css +27 -0
- solokit/templates/fullstack_nextjs/base/app/layout.tsx +20 -0
- solokit/templates/fullstack_nextjs/base/app/page.tsx +32 -0
- solokit/templates/fullstack_nextjs/base/components/example-component.tsx +20 -0
- solokit/templates/fullstack_nextjs/base/lib/prisma.ts +17 -0
- solokit/templates/fullstack_nextjs/base/lib/utils.ts +13 -0
- solokit/templates/fullstack_nextjs/base/lib/validations.ts +20 -0
- solokit/templates/fullstack_nextjs/base/next.config.ts +7 -0
- solokit/templates/fullstack_nextjs/base/package.json.template +32 -0
- solokit/templates/fullstack_nextjs/base/postcss.config.mjs +8 -0
- solokit/templates/fullstack_nextjs/base/prisma/schema.prisma +21 -0
- solokit/templates/fullstack_nextjs/base/tailwind.config.ts +19 -0
- solokit/templates/fullstack_nextjs/base/tsconfig.json +27 -0
- solokit/templates/fullstack_nextjs/docker/Dockerfile +60 -0
- solokit/templates/fullstack_nextjs/docker/docker-compose.prod.yml +57 -0
- solokit/templates/fullstack_nextjs/docker/docker-compose.yml +47 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/.eslintrc.json +7 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/jest.config.ts +17 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/jest.setup.ts +1 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/package.json.tier1.template +48 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/tests/api/example.test.ts +88 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/tests/setup.ts +22 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/tests/unit/example.test.tsx +22 -0
- solokit/templates/fullstack_nextjs/tier-2-standard/package.json.tier2.template +52 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/eslint.config.mjs +39 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/package.json.tier3.template +68 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/playwright.config.ts +66 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/stryker.conf.json +33 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/tests/e2e/flow.spec.ts +59 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/tests/integration/api.test.ts +165 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/type-coverage.json +12 -0
- solokit/templates/fullstack_nextjs/tier-4-production/instrumentation.ts +9 -0
- solokit/templates/fullstack_nextjs/tier-4-production/k6/load-test.js +45 -0
- solokit/templates/fullstack_nextjs/tier-4-production/next.config.ts +46 -0
- solokit/templates/fullstack_nextjs/tier-4-production/package.json.tier4.template +77 -0
- solokit/templates/fullstack_nextjs/tier-4-production/sentry.client.config.ts +26 -0
- solokit/templates/fullstack_nextjs/tier-4-production/sentry.edge.config.ts +11 -0
- solokit/templates/fullstack_nextjs/tier-4-production/sentry.server.config.ts +11 -0
- solokit/templates/git-hooks/prepare-commit-msg +24 -0
- solokit/templates/integration_test_spec.md +363 -0
- solokit/templates/learnings.json +15 -0
- solokit/templates/ml_ai_fastapi/base/.gitignore +104 -0
- solokit/templates/ml_ai_fastapi/base/alembic/env.py +96 -0
- solokit/templates/ml_ai_fastapi/base/alembic.ini +114 -0
- solokit/templates/ml_ai_fastapi/base/pyproject.toml.template +91 -0
- solokit/templates/ml_ai_fastapi/base/requirements.txt.template +28 -0
- solokit/templates/ml_ai_fastapi/base/src/__init__.py +5 -0
- solokit/templates/ml_ai_fastapi/base/src/api/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/base/src/api/dependencies.py +20 -0
- solokit/templates/ml_ai_fastapi/base/src/api/routes/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/base/src/api/routes/example.py +134 -0
- solokit/templates/ml_ai_fastapi/base/src/api/routes/health.py +66 -0
- solokit/templates/ml_ai_fastapi/base/src/core/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/base/src/core/config.py +64 -0
- solokit/templates/ml_ai_fastapi/base/src/core/database.py +50 -0
- solokit/templates/ml_ai_fastapi/base/src/main.py +64 -0
- solokit/templates/ml_ai_fastapi/base/src/models/__init__.py +7 -0
- solokit/templates/ml_ai_fastapi/base/src/models/example.py +61 -0
- solokit/templates/ml_ai_fastapi/base/src/services/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/base/src/services/example.py +115 -0
- solokit/templates/ml_ai_fastapi/docker/Dockerfile +59 -0
- solokit/templates/ml_ai_fastapi/docker/docker-compose.prod.yml +112 -0
- solokit/templates/ml_ai_fastapi/docker/docker-compose.yml +77 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/pyproject.toml.tier1.template +112 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/pyrightconfig.json +41 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/pytest.ini +69 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/requirements-dev.txt +17 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/ruff.toml +81 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/tests/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/tests/conftest.py +72 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/tests/test_main.py +49 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/tests/unit/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/tests/unit/test_example.py +113 -0
- solokit/templates/ml_ai_fastapi/tier-2-standard/pyproject.toml.tier2.template +130 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/locustfile.py +99 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/mutmut_config.py +53 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/pyproject.toml.tier3.template +150 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/tests/integration/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/tests/integration/conftest.py +74 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/tests/integration/test_api.py +131 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/pyproject.toml.tier4.template +162 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/requirements-prod.txt +25 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/api/routes/metrics.py +19 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/core/logging.py +74 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/core/monitoring.py +68 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/core/sentry.py +66 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/middleware/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/middleware/logging.py +79 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/middleware/tracing.py +60 -0
- solokit/templates/refactor_spec.md +287 -0
- solokit/templates/saas_t3/base/.gitignore +36 -0
- solokit/templates/saas_t3/base/app/api/trpc/[trpc]/route.ts +33 -0
- solokit/templates/saas_t3/base/app/globals.css +27 -0
- solokit/templates/saas_t3/base/app/layout.tsx +23 -0
- solokit/templates/saas_t3/base/app/page.tsx +31 -0
- solokit/templates/saas_t3/base/lib/api.tsx +77 -0
- solokit/templates/saas_t3/base/lib/utils.ts +13 -0
- solokit/templates/saas_t3/base/next.config.ts +7 -0
- solokit/templates/saas_t3/base/package.json.template +38 -0
- solokit/templates/saas_t3/base/postcss.config.mjs +8 -0
- solokit/templates/saas_t3/base/prisma/schema.prisma +20 -0
- solokit/templates/saas_t3/base/server/api/root.ts +19 -0
- solokit/templates/saas_t3/base/server/api/routers/example.ts +28 -0
- solokit/templates/saas_t3/base/server/api/trpc.ts +52 -0
- solokit/templates/saas_t3/base/server/db.ts +17 -0
- solokit/templates/saas_t3/base/tailwind.config.ts +19 -0
- solokit/templates/saas_t3/base/tsconfig.json +27 -0
- solokit/templates/saas_t3/docker/Dockerfile +60 -0
- solokit/templates/saas_t3/docker/docker-compose.prod.yml +59 -0
- solokit/templates/saas_t3/docker/docker-compose.yml +49 -0
- solokit/templates/saas_t3/tier-1-essential/.eslintrc.json +7 -0
- solokit/templates/saas_t3/tier-1-essential/jest.config.ts +17 -0
- solokit/templates/saas_t3/tier-1-essential/jest.setup.ts +1 -0
- solokit/templates/saas_t3/tier-1-essential/package.json.tier1.template +54 -0
- solokit/templates/saas_t3/tier-1-essential/tests/setup.ts +22 -0
- solokit/templates/saas_t3/tier-1-essential/tests/unit/example.test.tsx +24 -0
- solokit/templates/saas_t3/tier-2-standard/package.json.tier2.template +58 -0
- solokit/templates/saas_t3/tier-3-comprehensive/eslint.config.mjs +39 -0
- solokit/templates/saas_t3/tier-3-comprehensive/package.json.tier3.template +74 -0
- solokit/templates/saas_t3/tier-3-comprehensive/playwright.config.ts +66 -0
- solokit/templates/saas_t3/tier-3-comprehensive/stryker.conf.json +34 -0
- solokit/templates/saas_t3/tier-3-comprehensive/tests/e2e/home.spec.ts +41 -0
- solokit/templates/saas_t3/tier-3-comprehensive/tests/integration/api.test.ts +44 -0
- solokit/templates/saas_t3/tier-3-comprehensive/type-coverage.json +12 -0
- solokit/templates/saas_t3/tier-4-production/instrumentation.ts +9 -0
- solokit/templates/saas_t3/tier-4-production/k6/load-test.js +51 -0
- solokit/templates/saas_t3/tier-4-production/next.config.ts +46 -0
- solokit/templates/saas_t3/tier-4-production/package.json.tier4.template +83 -0
- solokit/templates/saas_t3/tier-4-production/sentry.client.config.ts +26 -0
- solokit/templates/saas_t3/tier-4-production/sentry.edge.config.ts +11 -0
- solokit/templates/saas_t3/tier-4-production/sentry.server.config.ts +11 -0
- solokit/templates/saas_t3/tier-4-production/vercel.json +37 -0
- solokit/templates/security_spec.md +287 -0
- solokit/templates/stack-versions.yaml +617 -0
- solokit/templates/status_update.json +6 -0
- solokit/templates/template-registry.json +257 -0
- solokit/templates/work_items.json +11 -0
- solokit/testing/__init__.py +1 -0
- solokit/testing/integration_runner.py +550 -0
- solokit/testing/performance.py +637 -0
- solokit/visualization/__init__.py +1 -0
- solokit/visualization/dependency_graph.py +788 -0
- solokit/work_items/__init__.py +1 -0
- solokit/work_items/creator.py +217 -0
- solokit/work_items/delete.py +264 -0
- solokit/work_items/get_dependencies.py +185 -0
- solokit/work_items/get_dependents.py +113 -0
- solokit/work_items/get_metadata.py +121 -0
- solokit/work_items/get_next_recommendations.py +133 -0
- solokit/work_items/manager.py +235 -0
- solokit/work_items/milestones.py +137 -0
- solokit/work_items/query.py +376 -0
- solokit/work_items/repository.py +267 -0
- solokit/work_items/scheduler.py +184 -0
- solokit/work_items/spec_parser.py +838 -0
- solokit/work_items/spec_validator.py +493 -0
- solokit/work_items/updater.py +157 -0
- solokit/work_items/validator.py +205 -0
- solokit-0.1.1.dist-info/METADATA +640 -0
- solokit-0.1.1.dist-info/RECORD +323 -0
- solokit-0.1.1.dist-info/WHEEL +5 -0
- solokit-0.1.1.dist-info/entry_points.txt +2 -0
- solokit-0.1.1.dist-info/licenses/LICENSE +21 -0
- solokit-0.1.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Session briefing orchestrator.
|
|
4
|
+
Coordinates all briefing components to generate comprehensive session briefings.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from solokit.core.exceptions import GitError, SystemError
|
|
12
|
+
from solokit.core.logging_config import get_logger
|
|
13
|
+
|
|
14
|
+
from .documentation_loader import DocumentationLoader
|
|
15
|
+
from .formatter import BriefingFormatter
|
|
16
|
+
from .git_context import GitContext
|
|
17
|
+
from .learning_loader import LearningLoader
|
|
18
|
+
from .milestone_builder import MilestoneBuilder
|
|
19
|
+
from .stack_detector import StackDetector
|
|
20
|
+
from .tree_generator import TreeGenerator
|
|
21
|
+
from .work_item_loader import WorkItemLoader
|
|
22
|
+
|
|
23
|
+
logger = get_logger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class SessionBriefing:
|
|
27
|
+
"""Orchestrate generation of comprehensive session briefings."""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
session_dir: Path | None = None,
|
|
32
|
+
project_root: Path | None = None,
|
|
33
|
+
):
|
|
34
|
+
"""Initialize session briefing orchestrator.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
session_dir: Path to .session directory (defaults to .session)
|
|
38
|
+
project_root: Path to project root (defaults to current directory)
|
|
39
|
+
"""
|
|
40
|
+
self.session_dir = session_dir or Path(".session")
|
|
41
|
+
self.project_root = project_root or Path.cwd()
|
|
42
|
+
|
|
43
|
+
# Initialize all component modules
|
|
44
|
+
self.work_item_loader = WorkItemLoader(session_dir=self.session_dir)
|
|
45
|
+
self.learning_loader = LearningLoader(session_dir=self.session_dir)
|
|
46
|
+
self.doc_loader = DocumentationLoader(project_root=self.project_root)
|
|
47
|
+
self.stack_detector = StackDetector(session_dir=self.session_dir)
|
|
48
|
+
self.tree_generator = TreeGenerator(session_dir=self.session_dir)
|
|
49
|
+
self.git_context = GitContext()
|
|
50
|
+
self.milestone_builder = MilestoneBuilder(session_dir=self.session_dir)
|
|
51
|
+
self.formatter = BriefingFormatter()
|
|
52
|
+
|
|
53
|
+
def generate_briefing(self, item_id: str, item: dict, learnings_data: dict) -> str:
|
|
54
|
+
"""Generate comprehensive markdown briefing with full project context.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
item_id: Work item identifier
|
|
58
|
+
item: Work item dictionary
|
|
59
|
+
learnings_data: Full learnings data structure
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
Complete briefing as markdown string
|
|
63
|
+
"""
|
|
64
|
+
# Load all context using specialized modules
|
|
65
|
+
project_docs = self.doc_loader.load_project_docs()
|
|
66
|
+
current_stack = self.stack_detector.load_current_stack()
|
|
67
|
+
current_tree = self.tree_generator.load_current_tree()
|
|
68
|
+
work_item_spec = self.work_item_loader.load_work_item_spec(item)
|
|
69
|
+
env_checks = self.formatter.validate_environment()
|
|
70
|
+
|
|
71
|
+
# Check git status - gracefully handle errors as this is informational
|
|
72
|
+
try:
|
|
73
|
+
git_status = self.git_context.check_git_status()
|
|
74
|
+
except (GitError, SystemError) as e:
|
|
75
|
+
logger.warning(f"Failed to check git status: {e.message}")
|
|
76
|
+
git_status = {"clean": False, "status": f"Error: {e.message}", "branch": None}
|
|
77
|
+
|
|
78
|
+
# Validate spec completeness
|
|
79
|
+
spec_validation_warning = self._validate_spec(item_id, item["type"])
|
|
80
|
+
|
|
81
|
+
# Get milestone context
|
|
82
|
+
milestone_context = self.milestone_builder.load_milestone_context(item)
|
|
83
|
+
|
|
84
|
+
# Get relevant learnings
|
|
85
|
+
relevant_learnings = self.learning_loader.get_relevant_learnings(
|
|
86
|
+
learnings_data, item, work_item_spec
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
# Generate briefing using formatter
|
|
90
|
+
return self.formatter.generate_briefing(
|
|
91
|
+
item_id=item_id,
|
|
92
|
+
item=item,
|
|
93
|
+
project_docs=project_docs,
|
|
94
|
+
current_stack=current_stack,
|
|
95
|
+
current_tree=current_tree,
|
|
96
|
+
work_item_spec=work_item_spec,
|
|
97
|
+
env_checks=env_checks,
|
|
98
|
+
git_status=git_status,
|
|
99
|
+
spec_validation_warning=spec_validation_warning,
|
|
100
|
+
milestone_context=milestone_context,
|
|
101
|
+
relevant_learnings=relevant_learnings,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
def _validate_spec(self, item_id: str, work_item_type: str) -> str | None:
|
|
105
|
+
"""Validate spec completeness and return warning if incomplete.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
item_id: Work item identifier
|
|
109
|
+
work_item_type: Type of work item
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Validation warning string or None if valid
|
|
113
|
+
"""
|
|
114
|
+
try:
|
|
115
|
+
from solokit.core.exceptions import FileNotFoundError as SolokitFileNotFoundError
|
|
116
|
+
from solokit.core.exceptions import SpecValidationError
|
|
117
|
+
from solokit.work_items.spec_validator import (
|
|
118
|
+
format_validation_report,
|
|
119
|
+
validate_spec_file,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
validate_spec_file(item_id, work_item_type)
|
|
124
|
+
# If no exception, spec is valid
|
|
125
|
+
return None
|
|
126
|
+
except SpecValidationError as e:
|
|
127
|
+
# Spec has validation errors
|
|
128
|
+
return format_validation_report(item_id, work_item_type, e)
|
|
129
|
+
except (SolokitFileNotFoundError, Exception):
|
|
130
|
+
# Spec file doesn't exist or other error - this is not critical for briefing
|
|
131
|
+
# Just return None and let the briefing proceed
|
|
132
|
+
return None
|
|
133
|
+
except ImportError:
|
|
134
|
+
# Gracefully handle if spec_validator not available
|
|
135
|
+
logger.debug("Spec validator not available")
|
|
136
|
+
|
|
137
|
+
return None
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Technology stack detection and information loading.
|
|
4
|
+
Part of the briefing module decomposition.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from solokit.core.error_handlers import log_errors
|
|
12
|
+
from solokit.core.exceptions import FileOperationError
|
|
13
|
+
from solokit.core.logging_config import get_logger
|
|
14
|
+
|
|
15
|
+
logger = get_logger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class StackDetector:
|
|
19
|
+
"""Detect and load technology stack information."""
|
|
20
|
+
|
|
21
|
+
def __init__(self, session_dir: Path | None = None):
|
|
22
|
+
"""Initialize stack detector.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
session_dir: Path to .session directory (defaults to .session)
|
|
26
|
+
"""
|
|
27
|
+
self.session_dir = session_dir or Path(".session")
|
|
28
|
+
self.stack_file = self.session_dir / "tracking" / "stack.txt"
|
|
29
|
+
|
|
30
|
+
@log_errors()
|
|
31
|
+
def load_current_stack(self) -> str:
|
|
32
|
+
"""Load current technology stack.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
Stack information as string
|
|
36
|
+
|
|
37
|
+
Raises:
|
|
38
|
+
FileOperationError: If stack file exists but cannot be read
|
|
39
|
+
"""
|
|
40
|
+
if not self.stack_file.exists():
|
|
41
|
+
return "Stack not yet generated"
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
return self.stack_file.read_text()
|
|
45
|
+
except OSError as e:
|
|
46
|
+
raise FileOperationError(
|
|
47
|
+
operation="read",
|
|
48
|
+
file_path=str(self.stack_file),
|
|
49
|
+
details=f"Failed to read stack file: {e}",
|
|
50
|
+
cause=e,
|
|
51
|
+
) from e
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Project directory tree loading.
|
|
4
|
+
Part of the briefing module decomposition.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from solokit.core.error_handlers import log_errors
|
|
12
|
+
from solokit.core.exceptions import FileOperationError
|
|
13
|
+
from solokit.core.logging_config import get_logger
|
|
14
|
+
|
|
15
|
+
logger = get_logger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TreeGenerator:
|
|
19
|
+
"""Load and generate project directory tree."""
|
|
20
|
+
|
|
21
|
+
def __init__(self, session_dir: Path | None = None):
|
|
22
|
+
"""Initialize tree generator.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
session_dir: Path to .session directory (defaults to .session)
|
|
26
|
+
"""
|
|
27
|
+
self.session_dir = session_dir or Path(".session")
|
|
28
|
+
self.tree_file = self.session_dir / "tracking" / "tree.txt"
|
|
29
|
+
|
|
30
|
+
@log_errors()
|
|
31
|
+
def load_current_tree(self) -> str:
|
|
32
|
+
"""Load current project structure.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
Project tree as string
|
|
36
|
+
|
|
37
|
+
Raises:
|
|
38
|
+
FileOperationError: If tree file exists but cannot be read
|
|
39
|
+
"""
|
|
40
|
+
if not self.tree_file.exists():
|
|
41
|
+
return "Tree not yet generated"
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
# Return full tree
|
|
45
|
+
return self.tree_file.read_text()
|
|
46
|
+
except OSError as e:
|
|
47
|
+
raise FileOperationError(
|
|
48
|
+
operation="read",
|
|
49
|
+
file_path=str(self.tree_file),
|
|
50
|
+
details=f"Failed to read tree file: {e}",
|
|
51
|
+
cause=e,
|
|
52
|
+
) from e
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Work item loading and dependency resolution.
|
|
4
|
+
Part of the briefing module decomposition.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
from solokit.core.logging_config import get_logger
|
|
15
|
+
from solokit.core.types import Priority, WorkItemStatus
|
|
16
|
+
|
|
17
|
+
logger = get_logger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class WorkItemLoader:
|
|
21
|
+
"""Load work items and their dependencies."""
|
|
22
|
+
|
|
23
|
+
def __init__(self, session_dir: Path | None = None):
|
|
24
|
+
"""Initialize work item loader.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
session_dir: Path to .session directory (defaults to .session)
|
|
28
|
+
"""
|
|
29
|
+
self.session_dir = session_dir or Path(".session")
|
|
30
|
+
self.work_items_file = self.session_dir / "tracking" / "work_items.json"
|
|
31
|
+
|
|
32
|
+
def load_work_items(self) -> dict[str, Any]:
|
|
33
|
+
"""Load work items from tracking file.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
Work items data structure with 'work_items' dict
|
|
37
|
+
"""
|
|
38
|
+
logger.debug("Loading work items from: %s", self.work_items_file)
|
|
39
|
+
if not self.work_items_file.exists():
|
|
40
|
+
logger.warning("Work items file not found: %s", self.work_items_file)
|
|
41
|
+
return {"work_items": {}}
|
|
42
|
+
with open(self.work_items_file) as f:
|
|
43
|
+
return json.load(f) # type: ignore[no-any-return]
|
|
44
|
+
|
|
45
|
+
def get_work_item(
|
|
46
|
+
self, work_item_id: str, work_items_data: dict[str, Any] | None = None
|
|
47
|
+
) -> dict[str, Any] | None:
|
|
48
|
+
"""Get a specific work item by ID.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
work_item_id: Work item identifier
|
|
52
|
+
work_items_data: Pre-loaded work items data (optional)
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
Work item dict or None if not found
|
|
56
|
+
"""
|
|
57
|
+
if work_items_data is None:
|
|
58
|
+
work_items_data = self.load_work_items()
|
|
59
|
+
|
|
60
|
+
return work_items_data.get("work_items", {}).get(work_item_id) # type: ignore[no-any-return]
|
|
61
|
+
|
|
62
|
+
def get_next_work_item(self, work_items_data: dict) -> tuple[str | None, dict | None]:
|
|
63
|
+
"""Find next available work item where dependencies are satisfied.
|
|
64
|
+
|
|
65
|
+
Prioritizes resuming in-progress items over starting new work.
|
|
66
|
+
Returns item with highest priority among available.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
work_items_data: Loaded work items data structure
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
Tuple of (item_id, item) or (None, None) if no work available
|
|
73
|
+
"""
|
|
74
|
+
work_items = work_items_data.get("work_items", {})
|
|
75
|
+
priority_order = {
|
|
76
|
+
Priority.CRITICAL.value: 4,
|
|
77
|
+
Priority.HIGH.value: 3,
|
|
78
|
+
Priority.MEDIUM.value: 2,
|
|
79
|
+
Priority.LOW.value: 1,
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
# PRIORITY 1: Resume in-progress work
|
|
83
|
+
in_progress_items = []
|
|
84
|
+
for item_id, item in work_items.items():
|
|
85
|
+
if item["status"] == WorkItemStatus.IN_PROGRESS.value:
|
|
86
|
+
in_progress_items.append((item_id, item))
|
|
87
|
+
|
|
88
|
+
if in_progress_items:
|
|
89
|
+
# Sort by priority and return highest
|
|
90
|
+
in_progress_items.sort(
|
|
91
|
+
key=lambda x: priority_order.get(x[1].get("priority", Priority.MEDIUM.value), 2),
|
|
92
|
+
reverse=True,
|
|
93
|
+
)
|
|
94
|
+
return in_progress_items[0]
|
|
95
|
+
|
|
96
|
+
# PRIORITY 2: Start new work
|
|
97
|
+
available = []
|
|
98
|
+
for item_id, item in work_items.items():
|
|
99
|
+
if item["status"] != WorkItemStatus.NOT_STARTED.value:
|
|
100
|
+
continue
|
|
101
|
+
|
|
102
|
+
# Check dependencies
|
|
103
|
+
deps_satisfied = all(
|
|
104
|
+
work_items.get(dep_id, {}).get("status") == WorkItemStatus.COMPLETED.value
|
|
105
|
+
for dep_id in item.get("dependencies", [])
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
if deps_satisfied:
|
|
109
|
+
available.append((item_id, item))
|
|
110
|
+
|
|
111
|
+
if not available:
|
|
112
|
+
return None, None
|
|
113
|
+
|
|
114
|
+
# Sort by priority
|
|
115
|
+
available.sort(
|
|
116
|
+
key=lambda x: priority_order.get(x[1].get("priority", Priority.MEDIUM.value), 2),
|
|
117
|
+
reverse=True,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
return available[0]
|
|
121
|
+
|
|
122
|
+
def load_work_item_spec(self, work_item: str | dict[str, Any]) -> str:
|
|
123
|
+
"""Load work item specification file.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
work_item: Either a work item dict with 'spec_file' and 'id' fields,
|
|
127
|
+
or a string work_item_id (for backwards compatibility)
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
Specification content as string
|
|
131
|
+
"""
|
|
132
|
+
# Handle backwards compatibility: accept both dict and string
|
|
133
|
+
if isinstance(work_item, str):
|
|
134
|
+
# Legacy call with just work_item_id string
|
|
135
|
+
work_item_id = work_item
|
|
136
|
+
spec_file = self.session_dir / "specs" / f"{work_item_id}.md"
|
|
137
|
+
else:
|
|
138
|
+
# New call with work item dict
|
|
139
|
+
# Use spec_file from work item if available, otherwise fallback to ID-based pattern
|
|
140
|
+
spec_file_path = work_item.get("spec_file")
|
|
141
|
+
if spec_file_path:
|
|
142
|
+
spec_file = Path(spec_file_path)
|
|
143
|
+
else:
|
|
144
|
+
# Fallback to legacy pattern for backwards compatibility
|
|
145
|
+
work_item_id_raw = work_item.get("id")
|
|
146
|
+
if not work_item_id_raw:
|
|
147
|
+
return "Specification file not found: work item has no id"
|
|
148
|
+
spec_file = self.session_dir / "specs" / f"{work_item_id_raw}.md"
|
|
149
|
+
|
|
150
|
+
if spec_file.exists():
|
|
151
|
+
return spec_file.read_text()
|
|
152
|
+
return f"Specification file not found: {spec_file}"
|
|
153
|
+
|
|
154
|
+
def update_work_item_status(
|
|
155
|
+
self, work_item_id: str, status: str, session_num: int | None = None
|
|
156
|
+
) -> bool:
|
|
157
|
+
"""Update work item status and optionally add session tracking.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
work_item_id: Work item identifier
|
|
161
|
+
status: New status value
|
|
162
|
+
session_num: Optional session number to add to tracking
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
True if update successful, False otherwise
|
|
166
|
+
"""
|
|
167
|
+
if not self.work_items_file.exists():
|
|
168
|
+
logger.error("Work items file not found: %s", self.work_items_file)
|
|
169
|
+
return False
|
|
170
|
+
|
|
171
|
+
with open(self.work_items_file) as f:
|
|
172
|
+
work_items_data = json.load(f)
|
|
173
|
+
|
|
174
|
+
if work_item_id not in work_items_data["work_items"]:
|
|
175
|
+
logger.error("Work item not found: %s", work_item_id)
|
|
176
|
+
return False
|
|
177
|
+
|
|
178
|
+
work_item = work_items_data["work_items"][work_item_id]
|
|
179
|
+
work_item["status"] = status
|
|
180
|
+
work_item["updated_at"] = datetime.now().isoformat()
|
|
181
|
+
|
|
182
|
+
# Add session tracking if session_num provided
|
|
183
|
+
if session_num is not None:
|
|
184
|
+
if "sessions" not in work_item:
|
|
185
|
+
work_item["sessions"] = []
|
|
186
|
+
work_item["sessions"].append(
|
|
187
|
+
{"session_num": session_num, "started_at": datetime.now().isoformat()}
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
# Update metadata counters
|
|
191
|
+
work_items = work_items_data.get("work_items", {})
|
|
192
|
+
work_items_data["metadata"]["total_items"] = len(work_items)
|
|
193
|
+
work_items_data["metadata"]["completed"] = sum(
|
|
194
|
+
1 for item in work_items.values() if item["status"] == WorkItemStatus.COMPLETED.value
|
|
195
|
+
)
|
|
196
|
+
work_items_data["metadata"]["in_progress"] = sum(
|
|
197
|
+
1 for item in work_items.values() if item["status"] == WorkItemStatus.IN_PROGRESS.value
|
|
198
|
+
)
|
|
199
|
+
work_items_data["metadata"]["blocked"] = sum(
|
|
200
|
+
1 for item in work_items.values() if item["status"] == WorkItemStatus.BLOCKED.value
|
|
201
|
+
)
|
|
202
|
+
work_items_data["metadata"]["last_updated"] = datetime.now().isoformat()
|
|
203
|
+
|
|
204
|
+
# Save updated work items
|
|
205
|
+
with open(self.work_items_file, "w") as f:
|
|
206
|
+
json.dump(work_items_data, f, indent=2)
|
|
207
|
+
|
|
208
|
+
logger.info("Updated work item %s status to %s", work_item_id, status)
|
|
209
|
+
return True
|