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,476 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Briefing formatting and generation.
|
|
4
|
+
Part of the briefing module decomposition.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
from solokit.core.command_runner import CommandRunner
|
|
12
|
+
from solokit.core.constants import SESSION_STATUS_TIMEOUT
|
|
13
|
+
from solokit.core.exceptions import (
|
|
14
|
+
FileOperationError,
|
|
15
|
+
)
|
|
16
|
+
from solokit.core.logging_config import get_logger
|
|
17
|
+
from solokit.core.types import WorkItemStatus, WorkItemType
|
|
18
|
+
|
|
19
|
+
logger = get_logger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class BriefingFormatter:
|
|
23
|
+
"""Format briefing content and generate output."""
|
|
24
|
+
|
|
25
|
+
def __init__(self) -> None:
|
|
26
|
+
"""Initialize briefing formatter."""
|
|
27
|
+
self.runner = CommandRunner(default_timeout=SESSION_STATUS_TIMEOUT)
|
|
28
|
+
|
|
29
|
+
def shift_heading_levels(self, markdown_content: str, shift: int) -> str:
|
|
30
|
+
r"""Shift all markdown heading levels by a specified amount.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
markdown_content: The markdown text to process
|
|
34
|
+
shift: Number of levels to shift (positive = deeper, e.g., H1 → H3 if shift=2)
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Modified markdown with shifted heading levels
|
|
38
|
+
|
|
39
|
+
Example:
|
|
40
|
+
shift_heading_levels("# Title\n## Section", 2)
|
|
41
|
+
Returns: "### Title\n#### Section"
|
|
42
|
+
"""
|
|
43
|
+
if not markdown_content or shift <= 0:
|
|
44
|
+
return markdown_content
|
|
45
|
+
|
|
46
|
+
lines = markdown_content.split("\n")
|
|
47
|
+
result = []
|
|
48
|
+
|
|
49
|
+
for line in lines:
|
|
50
|
+
# Check if line starts with heading marker
|
|
51
|
+
if line.startswith("#"):
|
|
52
|
+
# Count existing heading level
|
|
53
|
+
heading_level = 0
|
|
54
|
+
for char in line:
|
|
55
|
+
if char == "#":
|
|
56
|
+
heading_level += 1
|
|
57
|
+
else:
|
|
58
|
+
break
|
|
59
|
+
|
|
60
|
+
# Calculate new level (cap at 6 for markdown)
|
|
61
|
+
new_level = min(heading_level + shift, 6)
|
|
62
|
+
|
|
63
|
+
# Reconstruct line with new heading level
|
|
64
|
+
rest_of_line = line[heading_level:]
|
|
65
|
+
result.append("#" * new_level + rest_of_line)
|
|
66
|
+
else:
|
|
67
|
+
result.append(line)
|
|
68
|
+
|
|
69
|
+
return "\n".join(result)
|
|
70
|
+
|
|
71
|
+
def extract_section(self, markdown: str, heading: str) -> str:
|
|
72
|
+
"""Extract section from markdown between heading and next ## heading.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
markdown: Full markdown content
|
|
76
|
+
heading: Heading to find (e.g., "## Commits Made")
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Section content (without the heading itself)
|
|
80
|
+
"""
|
|
81
|
+
lines = markdown.split("\n")
|
|
82
|
+
section_lines = []
|
|
83
|
+
in_section = False
|
|
84
|
+
|
|
85
|
+
for line in lines:
|
|
86
|
+
if line.startswith(heading):
|
|
87
|
+
in_section = True
|
|
88
|
+
continue
|
|
89
|
+
elif in_section and line.startswith("## "):
|
|
90
|
+
break
|
|
91
|
+
elif in_section:
|
|
92
|
+
section_lines.append(line)
|
|
93
|
+
|
|
94
|
+
return "\n".join(section_lines).strip()
|
|
95
|
+
|
|
96
|
+
def generate_previous_work_section(self, item_id: str, item: dict) -> str:
|
|
97
|
+
"""Generate previous work context from session summaries.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
item_id: Work item identifier
|
|
101
|
+
item: Work item dictionary with sessions list
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
Markdown section with previous work context (empty string if none)
|
|
105
|
+
"""
|
|
106
|
+
sessions = item.get("sessions", [])
|
|
107
|
+
if not sessions:
|
|
108
|
+
return ""
|
|
109
|
+
|
|
110
|
+
section = "\n## Previous Work\n\n"
|
|
111
|
+
section += f"This work item has been in progress across {len(sessions)} session(s).\n\n"
|
|
112
|
+
|
|
113
|
+
for session_info in sessions:
|
|
114
|
+
session_num = session_info["session_num"]
|
|
115
|
+
started_at = session_info.get("started_at", "")
|
|
116
|
+
|
|
117
|
+
summary_file = Path(f".session/history/session_{session_num:03d}_summary.md")
|
|
118
|
+
if not summary_file.exists():
|
|
119
|
+
continue
|
|
120
|
+
|
|
121
|
+
try:
|
|
122
|
+
summary_content = summary_file.read_text()
|
|
123
|
+
except OSError as e:
|
|
124
|
+
raise FileOperationError(
|
|
125
|
+
operation="read",
|
|
126
|
+
file_path=str(summary_file),
|
|
127
|
+
details=f"Failed to read session summary: {str(e)}",
|
|
128
|
+
cause=e,
|
|
129
|
+
)
|
|
130
|
+
section += f"### Session {session_num} ({started_at[:10]})\n\n"
|
|
131
|
+
|
|
132
|
+
# Extract commits section
|
|
133
|
+
if "## Commits Made" in summary_content:
|
|
134
|
+
commits = self.extract_section(summary_content, "## Commits Made")
|
|
135
|
+
if commits:
|
|
136
|
+
section += commits + "\n\n"
|
|
137
|
+
|
|
138
|
+
# Extract quality gates
|
|
139
|
+
if "## Quality Gates" in summary_content:
|
|
140
|
+
gates = self.extract_section(summary_content, "## Quality Gates")
|
|
141
|
+
if gates:
|
|
142
|
+
section += "**Quality Gates:**\n" + gates + "\n\n"
|
|
143
|
+
|
|
144
|
+
return section
|
|
145
|
+
|
|
146
|
+
def validate_environment(self) -> list[str]:
|
|
147
|
+
"""Validate development environment.
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
List of environment check strings
|
|
151
|
+
"""
|
|
152
|
+
checks = []
|
|
153
|
+
|
|
154
|
+
# Check Python version
|
|
155
|
+
checks.append(f"Python: {sys.version.split()[0]}")
|
|
156
|
+
|
|
157
|
+
# Check git
|
|
158
|
+
result = self.runner.run(["git", "--version"])
|
|
159
|
+
if result.success:
|
|
160
|
+
checks.append(f"Git: {result.stdout.strip()}")
|
|
161
|
+
else:
|
|
162
|
+
checks.append("Git: NOT FOUND")
|
|
163
|
+
|
|
164
|
+
return checks
|
|
165
|
+
|
|
166
|
+
def check_command_exists(self, command: str) -> bool:
|
|
167
|
+
"""Check if a command is available.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
command: Command to check
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
True if command exists, False otherwise
|
|
174
|
+
"""
|
|
175
|
+
result = self.runner.run([command, "--version"])
|
|
176
|
+
return result.success
|
|
177
|
+
|
|
178
|
+
def generate_integration_test_briefing(self, work_item: dict) -> str:
|
|
179
|
+
"""Generate integration test specific briefing sections.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
work_item: Integration test work item
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
Additional briefing sections for integration tests
|
|
186
|
+
"""
|
|
187
|
+
if work_item.get("type") != WorkItemType.INTEGRATION_TEST.value:
|
|
188
|
+
return ""
|
|
189
|
+
|
|
190
|
+
briefing = "\n## Integration Test Context\n\n"
|
|
191
|
+
|
|
192
|
+
# 1. Components being integrated (from scope description)
|
|
193
|
+
scope = work_item.get("scope", "")
|
|
194
|
+
if scope and len(scope) > 20:
|
|
195
|
+
briefing += "**Integration Scope:**\n"
|
|
196
|
+
briefing += f"{scope[:200]}...\n\n" if len(scope) > 200 else f"{scope}\n\n"
|
|
197
|
+
|
|
198
|
+
# 2. Environment requirements
|
|
199
|
+
env_requirements = work_item.get("environment_requirements", {})
|
|
200
|
+
services = env_requirements.get("services_required", [])
|
|
201
|
+
|
|
202
|
+
if services:
|
|
203
|
+
briefing += "**Required Services:**\n"
|
|
204
|
+
for service in services:
|
|
205
|
+
briefing += f"- {service}\n"
|
|
206
|
+
briefing += "\n"
|
|
207
|
+
|
|
208
|
+
# 3. Test scenarios summary
|
|
209
|
+
scenarios = work_item.get("test_scenarios", [])
|
|
210
|
+
if scenarios:
|
|
211
|
+
briefing += f"**Test Scenarios ({len(scenarios)} total):**\n"
|
|
212
|
+
for i, scenario in enumerate(scenarios[:5], 1): # Show first 5
|
|
213
|
+
scenario_name = scenario.get("name", scenario.get("description", f"Scenario {i}"))
|
|
214
|
+
briefing += f"{i}. {scenario_name}\n"
|
|
215
|
+
|
|
216
|
+
if len(scenarios) > 5:
|
|
217
|
+
briefing += f"... and {len(scenarios) - 5} more scenarios\n"
|
|
218
|
+
briefing += "\n"
|
|
219
|
+
|
|
220
|
+
# 4. Performance benchmarks
|
|
221
|
+
benchmarks = work_item.get("performance_benchmarks", {})
|
|
222
|
+
if benchmarks:
|
|
223
|
+
briefing += "**Performance Requirements:**\n"
|
|
224
|
+
|
|
225
|
+
response_time = benchmarks.get("response_time", {})
|
|
226
|
+
if response_time:
|
|
227
|
+
briefing += f"- Response time: p95 < {response_time.get('p95', 'N/A')}ms\n"
|
|
228
|
+
|
|
229
|
+
throughput = benchmarks.get("throughput", {})
|
|
230
|
+
if throughput:
|
|
231
|
+
briefing += f"- Throughput: > {throughput.get('minimum', 'N/A')} req/s\n"
|
|
232
|
+
|
|
233
|
+
briefing += "\n"
|
|
234
|
+
|
|
235
|
+
# 5. API contracts
|
|
236
|
+
contracts = work_item.get("api_contracts", [])
|
|
237
|
+
if contracts:
|
|
238
|
+
briefing += f"**API Contracts ({len(contracts)} contracts):**\n"
|
|
239
|
+
for contract in contracts:
|
|
240
|
+
contract_file = contract.get("contract_file", "N/A")
|
|
241
|
+
contract_version = contract.get("version", "N/A")
|
|
242
|
+
briefing += f"- {contract_file} (version: {contract_version})\n"
|
|
243
|
+
briefing += "\n"
|
|
244
|
+
|
|
245
|
+
# 6. Environment validation status
|
|
246
|
+
briefing += "**Pre-Session Checks:**\n"
|
|
247
|
+
|
|
248
|
+
# Check Docker
|
|
249
|
+
docker_available = self.check_command_exists("docker")
|
|
250
|
+
briefing += f"- Docker: {'✓ Available' if docker_available else '✗ Not found'}\n"
|
|
251
|
+
|
|
252
|
+
# Check Docker Compose
|
|
253
|
+
compose_available = self.check_command_exists("docker-compose")
|
|
254
|
+
briefing += f"- Docker Compose: {'✓ Available' if compose_available else '✗ Not found'}\n"
|
|
255
|
+
|
|
256
|
+
# Check compose file
|
|
257
|
+
compose_file = env_requirements.get("compose_file", "docker-compose.integration.yml")
|
|
258
|
+
compose_exists = Path(compose_file).exists()
|
|
259
|
+
status_text = "✓ Found" if compose_exists else "✗ Missing"
|
|
260
|
+
briefing += f"- Compose file ({compose_file}): {status_text}\n"
|
|
261
|
+
|
|
262
|
+
briefing += "\n"
|
|
263
|
+
|
|
264
|
+
return briefing
|
|
265
|
+
|
|
266
|
+
def generate_deployment_briefing(self, work_item: dict) -> str:
|
|
267
|
+
"""Generate deployment-specific briefing section.
|
|
268
|
+
|
|
269
|
+
Args:
|
|
270
|
+
work_item: Deployment work item
|
|
271
|
+
|
|
272
|
+
Returns:
|
|
273
|
+
Deployment briefing text
|
|
274
|
+
"""
|
|
275
|
+
if work_item.get("type") != WorkItemType.DEPLOYMENT.value:
|
|
276
|
+
return ""
|
|
277
|
+
|
|
278
|
+
briefing = []
|
|
279
|
+
briefing.append("\n" + "=" * 60)
|
|
280
|
+
briefing.append("DEPLOYMENT CONTEXT")
|
|
281
|
+
briefing.append("=" * 60)
|
|
282
|
+
|
|
283
|
+
spec = work_item.get("specification", "")
|
|
284
|
+
|
|
285
|
+
# Parse deployment scope
|
|
286
|
+
briefing.append("\n**Deployment Scope:**")
|
|
287
|
+
# NOTE: Framework stub - Parse deployment scope from spec using spec_parser.py
|
|
288
|
+
# Extract "## Deployment Scope" section and parse Application/Environment/Version fields
|
|
289
|
+
briefing.append(" Application: [parse from spec]")
|
|
290
|
+
briefing.append(" Environment: [parse from spec]")
|
|
291
|
+
briefing.append(" Version: [parse from spec]")
|
|
292
|
+
|
|
293
|
+
# Parse deployment procedure
|
|
294
|
+
briefing.append("\n**Deployment Procedure:**")
|
|
295
|
+
# NOTE: Framework stub - Parse deployment steps from spec using spec_parser.py
|
|
296
|
+
# Extract "## Deployment Steps" section and count pre/during/post steps
|
|
297
|
+
briefing.append(" Pre-deployment: [X steps]")
|
|
298
|
+
briefing.append(" Deployment: [Y steps]")
|
|
299
|
+
briefing.append(" Post-deployment: [Z steps]")
|
|
300
|
+
|
|
301
|
+
# Parse rollback procedure
|
|
302
|
+
briefing.append("\n**Rollback Procedure:**")
|
|
303
|
+
# NOTE: Framework stub - Parse rollback details from spec using spec_parser.py
|
|
304
|
+
# Extract "## Rollback Procedure" section for triggers and time estimates
|
|
305
|
+
has_rollback = "rollback procedure" in spec.lower()
|
|
306
|
+
briefing.append(f" Rollback triggers defined: {'Yes' if has_rollback else 'No'}")
|
|
307
|
+
briefing.append(" Estimated rollback time: [X minutes]")
|
|
308
|
+
|
|
309
|
+
# Environment pre-checks
|
|
310
|
+
briefing.append("\n**Pre-Session Environment Checks:**")
|
|
311
|
+
try:
|
|
312
|
+
from solokit.quality.env_validator import EnvironmentValidator
|
|
313
|
+
|
|
314
|
+
# NOTE: Framework stub - Parse target environment from spec using spec_parser.py
|
|
315
|
+
# Extract from "## Deployment Scope" or "## Environment" section
|
|
316
|
+
environment = "staging" # Default fallback
|
|
317
|
+
validator = EnvironmentValidator(environment)
|
|
318
|
+
passed, results = validator.validate_all()
|
|
319
|
+
|
|
320
|
+
briefing.append(f" Environment validation: {'✓ PASSED' if passed else '✗ FAILED'}")
|
|
321
|
+
for validation in results.get("validations", []):
|
|
322
|
+
status = "✓" if validation["passed"] else "✗"
|
|
323
|
+
briefing.append(f" {status} {validation['name']}")
|
|
324
|
+
except ImportError as e:
|
|
325
|
+
logger.warning(
|
|
326
|
+
"EnvironmentValidator module not available",
|
|
327
|
+
extra={"error": str(e), "module": "solokit.quality.env_validator"},
|
|
328
|
+
)
|
|
329
|
+
briefing.append(" Environment validation: ✗ Module not available")
|
|
330
|
+
except Exception as e:
|
|
331
|
+
logger.error(
|
|
332
|
+
"Environment validation failed",
|
|
333
|
+
extra={"error": str(e), "environment": "staging"},
|
|
334
|
+
)
|
|
335
|
+
briefing.append(f" Environment validation: ✗ Error ({str(e)})")
|
|
336
|
+
|
|
337
|
+
briefing.append("\n" + "=" * 60)
|
|
338
|
+
|
|
339
|
+
return "\n".join(briefing)
|
|
340
|
+
|
|
341
|
+
def generate_briefing(
|
|
342
|
+
self,
|
|
343
|
+
item_id: str,
|
|
344
|
+
item: dict,
|
|
345
|
+
project_docs: dict[str, str],
|
|
346
|
+
current_stack: str,
|
|
347
|
+
current_tree: str,
|
|
348
|
+
work_item_spec: str,
|
|
349
|
+
env_checks: list[str],
|
|
350
|
+
git_status: dict,
|
|
351
|
+
spec_validation_warning: Optional[str],
|
|
352
|
+
milestone_context: Optional[dict],
|
|
353
|
+
relevant_learnings: list[dict],
|
|
354
|
+
) -> str:
|
|
355
|
+
"""Generate comprehensive markdown briefing with full project context.
|
|
356
|
+
|
|
357
|
+
Args:
|
|
358
|
+
item_id: Work item identifier
|
|
359
|
+
item: Work item dictionary
|
|
360
|
+
project_docs: Project documentation (dict of filename -> content)
|
|
361
|
+
current_stack: Technology stack information
|
|
362
|
+
current_tree: Project directory tree
|
|
363
|
+
work_item_spec: Work item specification content
|
|
364
|
+
env_checks: Environment validation checks
|
|
365
|
+
git_status: Git status information
|
|
366
|
+
spec_validation_warning: Optional spec validation warning
|
|
367
|
+
milestone_context: Optional milestone context
|
|
368
|
+
relevant_learnings: List of relevant learnings
|
|
369
|
+
|
|
370
|
+
Returns:
|
|
371
|
+
Complete briefing as markdown string
|
|
372
|
+
"""
|
|
373
|
+
# Start briefing
|
|
374
|
+
briefing = f"""# Session Briefing: {item["title"]}
|
|
375
|
+
|
|
376
|
+
## Quick Reference
|
|
377
|
+
- **Work Item ID:** {item_id}
|
|
378
|
+
- **Type:** {item["type"]}
|
|
379
|
+
- **Priority:** {item["priority"]}
|
|
380
|
+
- **Status:** {item["status"]}
|
|
381
|
+
|
|
382
|
+
## Environment Status
|
|
383
|
+
"""
|
|
384
|
+
|
|
385
|
+
# Show environment checks
|
|
386
|
+
for check in env_checks:
|
|
387
|
+
briefing += f"- {check}\n"
|
|
388
|
+
|
|
389
|
+
# Show git status
|
|
390
|
+
briefing += "\n### Git Status\n"
|
|
391
|
+
briefing += f"- Status: {git_status['status']}\n"
|
|
392
|
+
if git_status.get("branch"):
|
|
393
|
+
briefing += f"- Current Branch: {git_status['branch']}\n"
|
|
394
|
+
|
|
395
|
+
# Project context section
|
|
396
|
+
briefing += "\n## Project Context\n\n"
|
|
397
|
+
|
|
398
|
+
# Vision (if available) - shift headings to maintain hierarchy under H3
|
|
399
|
+
if "vision.md" in project_docs:
|
|
400
|
+
shifted_vision = self.shift_heading_levels(project_docs["vision.md"], 3)
|
|
401
|
+
briefing += f"### Vision\n\n{shifted_vision}\n\n"
|
|
402
|
+
|
|
403
|
+
# Architecture (if available) - shift headings to maintain hierarchy under H3
|
|
404
|
+
if "architecture.md" in project_docs:
|
|
405
|
+
shifted_arch = self.shift_heading_levels(project_docs["architecture.md"], 3)
|
|
406
|
+
briefing += f"### Architecture\n\n{shifted_arch}\n\n"
|
|
407
|
+
|
|
408
|
+
# Current stack
|
|
409
|
+
briefing += f"### Current Stack\n```\n{current_stack}\n```\n\n"
|
|
410
|
+
|
|
411
|
+
# Project structure - full tree
|
|
412
|
+
briefing += f"### Project Structure\n```\n{current_tree}\n```\n\n"
|
|
413
|
+
|
|
414
|
+
# Spec validation warning (if spec is incomplete)
|
|
415
|
+
if spec_validation_warning:
|
|
416
|
+
briefing += f"""## ⚠️ Specification Validation Warning
|
|
417
|
+
|
|
418
|
+
{spec_validation_warning}
|
|
419
|
+
|
|
420
|
+
**Note:** Please review and complete the specification before proceeding with implementation.
|
|
421
|
+
|
|
422
|
+
"""
|
|
423
|
+
|
|
424
|
+
# Add previous work section for in-progress items (Enhancement #11 Phase 3)
|
|
425
|
+
if item.get("status") == WorkItemStatus.IN_PROGRESS.value:
|
|
426
|
+
previous_work = self.generate_previous_work_section(item_id, item)
|
|
427
|
+
if previous_work:
|
|
428
|
+
briefing += previous_work
|
|
429
|
+
|
|
430
|
+
# Work item specification - shift headings to maintain hierarchy under H2
|
|
431
|
+
shifted_spec = self.shift_heading_levels(work_item_spec, 2)
|
|
432
|
+
briefing += f"""## Work Item Specification
|
|
433
|
+
|
|
434
|
+
{shifted_spec}
|
|
435
|
+
|
|
436
|
+
## Dependencies
|
|
437
|
+
"""
|
|
438
|
+
|
|
439
|
+
# Show dependency status
|
|
440
|
+
if item.get("dependencies"):
|
|
441
|
+
for dep in item["dependencies"]:
|
|
442
|
+
briefing += f"- {dep} ✓ completed\n"
|
|
443
|
+
else:
|
|
444
|
+
briefing += "No dependencies\n"
|
|
445
|
+
|
|
446
|
+
# Add milestone context
|
|
447
|
+
if milestone_context:
|
|
448
|
+
briefing += f"""
|
|
449
|
+
## Milestone Context
|
|
450
|
+
|
|
451
|
+
**{milestone_context["title"]}**
|
|
452
|
+
{milestone_context["description"]}
|
|
453
|
+
|
|
454
|
+
Progress: {milestone_context["progress"]}% ({milestone_context["completed_items"]}"""
|
|
455
|
+
briefing += f"""/{milestone_context["total_items"]} items complete)
|
|
456
|
+
"""
|
|
457
|
+
if milestone_context["target_date"]:
|
|
458
|
+
briefing += f"Target Date: {milestone_context['target_date']}\n"
|
|
459
|
+
|
|
460
|
+
briefing += "\nRelated work items in this milestone:\n"
|
|
461
|
+
# Show other items in same milestone
|
|
462
|
+
for related_item in milestone_context["milestone_items"]:
|
|
463
|
+
if related_item["id"] != item_id:
|
|
464
|
+
status_icon = (
|
|
465
|
+
"✓" if related_item["status"] == WorkItemStatus.COMPLETED.value else "○"
|
|
466
|
+
)
|
|
467
|
+
briefing += f"- {status_icon} {related_item['id']} - {related_item['title']}\n"
|
|
468
|
+
briefing += "\n"
|
|
469
|
+
|
|
470
|
+
# Relevant learnings
|
|
471
|
+
if relevant_learnings:
|
|
472
|
+
briefing += "\n## Relevant Learnings\n\n"
|
|
473
|
+
for learning in relevant_learnings:
|
|
474
|
+
briefing += f"**{learning.get('category', 'general')}:** {learning['content']}\n\n"
|
|
475
|
+
|
|
476
|
+
return briefing
|