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,353 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Generate session briefing for next work item.
|
|
4
|
+
Enhanced with full project context loading.
|
|
5
|
+
|
|
6
|
+
This module has been refactored into a package structure.
|
|
7
|
+
All functionality is now in solokit.session.briefing.* modules.
|
|
8
|
+
This file maintains the CLI entry point and backward compatibility.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
from solokit.core.error_handlers import log_errors
|
|
16
|
+
from solokit.core.exceptions import (
|
|
17
|
+
GitError,
|
|
18
|
+
SessionAlreadyActiveError,
|
|
19
|
+
SessionNotFoundError,
|
|
20
|
+
UnmetDependencyError,
|
|
21
|
+
ValidationError,
|
|
22
|
+
WorkItemNotFoundError,
|
|
23
|
+
)
|
|
24
|
+
from solokit.core.logging_config import get_logger
|
|
25
|
+
from solokit.core.output import get_output
|
|
26
|
+
from solokit.core.types import WorkItemStatus
|
|
27
|
+
|
|
28
|
+
# Import from refactored briefing package
|
|
29
|
+
from solokit.session.briefing import (
|
|
30
|
+
calculate_days_ago, # noqa: F401
|
|
31
|
+
check_command_exists, # noqa: F401
|
|
32
|
+
check_git_status, # noqa: F401
|
|
33
|
+
determine_git_branch_final_status, # noqa: F401
|
|
34
|
+
extract_keywords, # noqa: F401
|
|
35
|
+
extract_section, # noqa: F401
|
|
36
|
+
finalize_previous_work_item_git_status,
|
|
37
|
+
generate_briefing,
|
|
38
|
+
generate_deployment_briefing, # noqa: F401
|
|
39
|
+
generate_integration_test_briefing, # noqa: F401
|
|
40
|
+
generate_previous_work_section, # noqa: F401
|
|
41
|
+
get_next_work_item, # noqa: F401
|
|
42
|
+
get_relevant_learnings, # noqa: F401
|
|
43
|
+
load_current_stack, # noqa: F401
|
|
44
|
+
load_current_tree, # noqa: F401
|
|
45
|
+
load_learnings, # noqa: F401
|
|
46
|
+
load_milestone_context, # noqa: F401
|
|
47
|
+
load_project_docs, # noqa: F401
|
|
48
|
+
load_work_item_spec, # noqa: F401
|
|
49
|
+
load_work_items, # noqa: F401
|
|
50
|
+
shift_heading_levels, # noqa: F401
|
|
51
|
+
validate_environment, # noqa: F401
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
logger = get_logger(__name__)
|
|
55
|
+
output = get_output()
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@log_errors()
|
|
59
|
+
def main():
|
|
60
|
+
"""Main entry point for session briefing generation.
|
|
61
|
+
|
|
62
|
+
Raises:
|
|
63
|
+
SessionNotFoundError: If .session directory doesn't exist
|
|
64
|
+
WorkItemNotFoundError: If specified work item doesn't exist
|
|
65
|
+
SessionAlreadyActiveError: If another work item is in-progress (without --force)
|
|
66
|
+
UnmetDependencyError: If work item has unmet dependencies
|
|
67
|
+
ValidationError: If no available work items found
|
|
68
|
+
GitError: If git workflow fails
|
|
69
|
+
"""
|
|
70
|
+
import argparse
|
|
71
|
+
|
|
72
|
+
# Parse command-line arguments
|
|
73
|
+
parser = argparse.ArgumentParser(description="Start session for work item")
|
|
74
|
+
parser.add_argument(
|
|
75
|
+
"work_item_id",
|
|
76
|
+
nargs="?",
|
|
77
|
+
help="Specific work item ID to start (optional)",
|
|
78
|
+
)
|
|
79
|
+
parser.add_argument(
|
|
80
|
+
"--force",
|
|
81
|
+
action="store_true",
|
|
82
|
+
help="Force start even if another item is in-progress",
|
|
83
|
+
)
|
|
84
|
+
args = parser.parse_args()
|
|
85
|
+
|
|
86
|
+
logger.info("Starting session briefing generation")
|
|
87
|
+
|
|
88
|
+
# Ensure .session directory exists
|
|
89
|
+
session_dir = Path(".session")
|
|
90
|
+
if not session_dir.exists():
|
|
91
|
+
logger.error(".session directory not found")
|
|
92
|
+
raise SessionNotFoundError()
|
|
93
|
+
|
|
94
|
+
# Load data
|
|
95
|
+
work_items_data = load_work_items()
|
|
96
|
+
learnings_data = load_learnings()
|
|
97
|
+
|
|
98
|
+
# Determine which work item to start
|
|
99
|
+
if args.work_item_id:
|
|
100
|
+
# User specified a work item explicitly
|
|
101
|
+
item_id = args.work_item_id
|
|
102
|
+
item = work_items_data.get("work_items", {}).get(item_id)
|
|
103
|
+
|
|
104
|
+
if not item:
|
|
105
|
+
logger.error("Work item not found: %s", item_id)
|
|
106
|
+
raise WorkItemNotFoundError(item_id)
|
|
107
|
+
|
|
108
|
+
# Check if a DIFFERENT work item is in-progress (excluding the requested one)
|
|
109
|
+
in_progress = [
|
|
110
|
+
(id, wi)
|
|
111
|
+
for id, wi in work_items_data.get("work_items", {}).items()
|
|
112
|
+
if wi["status"] == WorkItemStatus.IN_PROGRESS.value and id != item_id
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
# If another item is in-progress, warn and exit (unless --force)
|
|
116
|
+
if in_progress and not args.force:
|
|
117
|
+
in_progress_id = in_progress[0][0]
|
|
118
|
+
logger.warning(
|
|
119
|
+
"Blocked start of %s due to in-progress item: %s (use --force to override)",
|
|
120
|
+
item_id,
|
|
121
|
+
in_progress_id,
|
|
122
|
+
)
|
|
123
|
+
raise SessionAlreadyActiveError(in_progress_id)
|
|
124
|
+
|
|
125
|
+
# Check dependencies are satisfied
|
|
126
|
+
deps_satisfied = all(
|
|
127
|
+
work_items_data.get("work_items", {}).get(dep_id, {}).get("status")
|
|
128
|
+
== WorkItemStatus.COMPLETED.value
|
|
129
|
+
for dep_id in item.get("dependencies", [])
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
if not deps_satisfied:
|
|
133
|
+
unmet_deps = [
|
|
134
|
+
dep_id
|
|
135
|
+
for dep_id in item.get("dependencies", [])
|
|
136
|
+
if work_items_data.get("work_items", {}).get(dep_id, {}).get("status")
|
|
137
|
+
!= "completed"
|
|
138
|
+
]
|
|
139
|
+
logger.error("Work item %s has unmet dependencies: %s", item_id, unmet_deps)
|
|
140
|
+
# Raise exception for the first unmet dependency
|
|
141
|
+
# (The exception message will indicate there are dependencies to complete)
|
|
142
|
+
raise UnmetDependencyError(item_id, unmet_deps[0])
|
|
143
|
+
|
|
144
|
+
# Note: If requested item is already in-progress, no conflict - just resume it
|
|
145
|
+
logger.info("User explicitly requested work item: %s", item_id)
|
|
146
|
+
else:
|
|
147
|
+
# Use automatic selection
|
|
148
|
+
item_id, item = get_next_work_item(work_items_data)
|
|
149
|
+
|
|
150
|
+
if not item_id:
|
|
151
|
+
logger.warning("No available work items found")
|
|
152
|
+
from solokit.core.exceptions import ErrorCode, ValidationError
|
|
153
|
+
|
|
154
|
+
raise ValidationError(
|
|
155
|
+
message="No available work items. All dependencies must be satisfied first.",
|
|
156
|
+
code=ErrorCode.INVALID_STATUS,
|
|
157
|
+
remediation="Complete dependencies or use 'sk work-list' to see work item status",
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
# Finalize previous work item's git status if starting a new work item
|
|
161
|
+
finalize_previous_work_item_git_status(work_items_data, item_id)
|
|
162
|
+
|
|
163
|
+
logger.info("Generating briefing for work item: %s", item_id)
|
|
164
|
+
# Generate briefing
|
|
165
|
+
briefing = generate_briefing(item_id, item, learnings_data)
|
|
166
|
+
|
|
167
|
+
# Save briefing
|
|
168
|
+
briefings_dir = session_dir / "briefings"
|
|
169
|
+
briefings_dir.mkdir(exist_ok=True)
|
|
170
|
+
|
|
171
|
+
# Determine session number
|
|
172
|
+
# If work item is already in progress, reuse existing session number
|
|
173
|
+
if item.get("status") == WorkItemStatus.IN_PROGRESS.value and item.get("sessions"):
|
|
174
|
+
session_num = item["sessions"][-1]["session_num"]
|
|
175
|
+
logger.info("Resuming existing session %d for work item %s", session_num, item_id)
|
|
176
|
+
else:
|
|
177
|
+
# Create new session number for new work or restarted work
|
|
178
|
+
session_num = (
|
|
179
|
+
max(
|
|
180
|
+
[int(f.stem.split("_")[1]) for f in briefings_dir.glob("session_*.md")],
|
|
181
|
+
default=0,
|
|
182
|
+
)
|
|
183
|
+
+ 1
|
|
184
|
+
)
|
|
185
|
+
logger.info("Starting new session %d for work item %s", session_num, item_id)
|
|
186
|
+
|
|
187
|
+
# Start git workflow for work item
|
|
188
|
+
try:
|
|
189
|
+
# Import git workflow from new location
|
|
190
|
+
from solokit.git.integration import GitWorkflow
|
|
191
|
+
|
|
192
|
+
workflow = GitWorkflow()
|
|
193
|
+
git_result = workflow.start_work_item(item_id, session_num)
|
|
194
|
+
|
|
195
|
+
if git_result["success"]:
|
|
196
|
+
if git_result["action"] == "created":
|
|
197
|
+
output.success(f"Created git branch: {git_result['branch']}\n")
|
|
198
|
+
else:
|
|
199
|
+
output.success(f"Resumed git branch: {git_result['branch']}\n")
|
|
200
|
+
else:
|
|
201
|
+
output.warning(f"Git workflow warning: {git_result['message']}\n")
|
|
202
|
+
except GitError:
|
|
203
|
+
# Re-raise GitError only if it's critical (not a git repo, command not found)
|
|
204
|
+
# Other git errors are logged as warnings but don't block the briefing
|
|
205
|
+
raise
|
|
206
|
+
except Exception as e:
|
|
207
|
+
# Log unexpected errors but don't block briefing generation
|
|
208
|
+
# Git workflow issues are non-fatal
|
|
209
|
+
logger.warning("Could not start git workflow: %s", e)
|
|
210
|
+
output.warning(f"Could not start git workflow: {e}\n")
|
|
211
|
+
|
|
212
|
+
# Update work item status and session tracking
|
|
213
|
+
work_items_file = session_dir / "tracking" / "work_items.json"
|
|
214
|
+
if work_items_file.exists():
|
|
215
|
+
with open(work_items_file) as f:
|
|
216
|
+
work_items_data = json.load(f)
|
|
217
|
+
|
|
218
|
+
# Update work item status
|
|
219
|
+
if item_id in work_items_data["work_items"]:
|
|
220
|
+
work_item = work_items_data["work_items"][item_id]
|
|
221
|
+
work_item["status"] = WorkItemStatus.IN_PROGRESS.value
|
|
222
|
+
work_item["updated_at"] = datetime.now().isoformat()
|
|
223
|
+
|
|
224
|
+
# Add session tracking
|
|
225
|
+
if "sessions" not in work_item:
|
|
226
|
+
work_item["sessions"] = []
|
|
227
|
+
work_item["sessions"].append(
|
|
228
|
+
{"session_num": session_num, "started_at": datetime.now().isoformat()}
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
# Update metadata counters
|
|
232
|
+
work_items = work_items_data.get("work_items", {})
|
|
233
|
+
work_items_data["metadata"]["total_items"] = len(work_items)
|
|
234
|
+
work_items_data["metadata"]["completed"] = sum(
|
|
235
|
+
1
|
|
236
|
+
for item in work_items.values()
|
|
237
|
+
if item["status"] == WorkItemStatus.COMPLETED.value
|
|
238
|
+
)
|
|
239
|
+
work_items_data["metadata"]["in_progress"] = sum(
|
|
240
|
+
1
|
|
241
|
+
for item in work_items.values()
|
|
242
|
+
if item["status"] == WorkItemStatus.IN_PROGRESS.value
|
|
243
|
+
)
|
|
244
|
+
work_items_data["metadata"]["blocked"] = sum(
|
|
245
|
+
1 for item in work_items.values() if item["status"] == WorkItemStatus.BLOCKED.value
|
|
246
|
+
)
|
|
247
|
+
work_items_data["metadata"]["last_updated"] = datetime.now().isoformat()
|
|
248
|
+
|
|
249
|
+
# Save updated work items
|
|
250
|
+
with open(work_items_file, "w") as f:
|
|
251
|
+
json.dump(work_items_data, f, indent=2)
|
|
252
|
+
|
|
253
|
+
# Notify that status has been updated
|
|
254
|
+
output.success(f"Work item status updated: {item_id} → in_progress\n")
|
|
255
|
+
|
|
256
|
+
briefing_file = briefings_dir / f"session_{session_num:03d}_briefing.md"
|
|
257
|
+
|
|
258
|
+
# Always write briefing file to include fresh context (Enhancement #11 Phase 2)
|
|
259
|
+
# This is critical for in-progress items to show previous work context
|
|
260
|
+
with open(briefing_file, "w") as f:
|
|
261
|
+
f.write(briefing)
|
|
262
|
+
|
|
263
|
+
if item.get("status") == WorkItemStatus.IN_PROGRESS.value:
|
|
264
|
+
logger.info("Updated briefing with previous work context: %s", briefing_file)
|
|
265
|
+
else:
|
|
266
|
+
logger.info("Created briefing file: %s", briefing_file)
|
|
267
|
+
|
|
268
|
+
# Print briefing (always show it, whether new or existing)
|
|
269
|
+
output.info(briefing)
|
|
270
|
+
|
|
271
|
+
# Update status file
|
|
272
|
+
status_file = session_dir / "tracking" / "status_update.json"
|
|
273
|
+
status = {
|
|
274
|
+
"current_session": session_num,
|
|
275
|
+
"current_work_item": item_id,
|
|
276
|
+
"started_at": datetime.now().isoformat(),
|
|
277
|
+
"status": WorkItemStatus.IN_PROGRESS.value,
|
|
278
|
+
}
|
|
279
|
+
with open(status_file, "w") as f:
|
|
280
|
+
json.dump(status, f, indent=2)
|
|
281
|
+
|
|
282
|
+
return 0
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def _cli_main():
|
|
286
|
+
"""CLI wrapper for main() that handles exceptions and exit codes."""
|
|
287
|
+
try:
|
|
288
|
+
return main()
|
|
289
|
+
except SessionNotFoundError as e:
|
|
290
|
+
output.info(f"Error: {e.message}")
|
|
291
|
+
output.info(f"\n{e.remediation}")
|
|
292
|
+
return e.exit_code
|
|
293
|
+
except WorkItemNotFoundError as e:
|
|
294
|
+
output.info(f"Error: {e.message}")
|
|
295
|
+
output.info(f"\n{e.remediation}")
|
|
296
|
+
# Also show available work items
|
|
297
|
+
try:
|
|
298
|
+
work_items_data = load_work_items()
|
|
299
|
+
output.info("\nAvailable work items:")
|
|
300
|
+
for wid, wi in work_items_data.get("work_items", {}).items():
|
|
301
|
+
status_emoji = {
|
|
302
|
+
WorkItemStatus.NOT_STARTED.value: "○",
|
|
303
|
+
WorkItemStatus.IN_PROGRESS.value: "◐",
|
|
304
|
+
WorkItemStatus.COMPLETED.value: "✓",
|
|
305
|
+
WorkItemStatus.BLOCKED.value: "✗",
|
|
306
|
+
}.get(wi["status"], "○")
|
|
307
|
+
output.info(f" {status_emoji} {wid} - {wi['title']} ({wi['status']})")
|
|
308
|
+
except Exception:
|
|
309
|
+
pass # If we can't load work items, just skip the list
|
|
310
|
+
return e.exit_code
|
|
311
|
+
except SessionAlreadyActiveError as e:
|
|
312
|
+
output.info(f"\nWarning: {e.message}")
|
|
313
|
+
output.info("\nOptions:")
|
|
314
|
+
output.info("1. Complete current work item first: /end")
|
|
315
|
+
output.info("2. Force start new work item: sk start <work_item_id> --force")
|
|
316
|
+
output.info("3. Cancel: Ctrl+C\n")
|
|
317
|
+
return e.exit_code
|
|
318
|
+
except UnmetDependencyError as e:
|
|
319
|
+
output.info(f"Error: {e.message}")
|
|
320
|
+
output.info(f"\n{e.remediation}")
|
|
321
|
+
# Show unmet dependency details
|
|
322
|
+
try:
|
|
323
|
+
work_items_data = load_work_items()
|
|
324
|
+
dep_id = e.context.get("dependency_id")
|
|
325
|
+
if dep_id:
|
|
326
|
+
dep = work_items_data.get("work_items", {}).get(dep_id, {})
|
|
327
|
+
output.info("\nDependency details:")
|
|
328
|
+
output.info(
|
|
329
|
+
f" - {dep_id}: {dep.get('title', 'Unknown')} (status: {dep.get('status', 'unknown')})"
|
|
330
|
+
)
|
|
331
|
+
except Exception:
|
|
332
|
+
pass # If we can't load work items, just skip the details
|
|
333
|
+
return e.exit_code
|
|
334
|
+
except ValidationError as e:
|
|
335
|
+
output.info(f"Error: {e.message}")
|
|
336
|
+
if e.remediation:
|
|
337
|
+
output.info(f"\n{e.remediation}")
|
|
338
|
+
return e.exit_code
|
|
339
|
+
except GitError as e:
|
|
340
|
+
output.info(f"Warning: {e.message}")
|
|
341
|
+
if e.remediation:
|
|
342
|
+
output.info(f"\n{e.remediation}")
|
|
343
|
+
# Git errors are warnings, not fatal - return success
|
|
344
|
+
# This maintains backwards compatibility
|
|
345
|
+
return 0
|
|
346
|
+
except Exception as e:
|
|
347
|
+
logger.exception("Unexpected error in briefing generation")
|
|
348
|
+
output.info(f"Unexpected error: {e}")
|
|
349
|
+
return 1
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
if __name__ == "__main__":
|
|
353
|
+
exit(_cli_main())
|