htmlgraph 0.9.3__py3-none-any.whl → 0.27.5__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.
- htmlgraph/.htmlgraph/.session-warning-state.json +6 -0
- htmlgraph/.htmlgraph/agents.json +72 -0
- htmlgraph/.htmlgraph/htmlgraph.db +0 -0
- htmlgraph/__init__.py +173 -17
- htmlgraph/__init__.pyi +123 -0
- htmlgraph/agent_detection.py +127 -0
- htmlgraph/agent_registry.py +45 -30
- htmlgraph/agents.py +160 -107
- htmlgraph/analytics/__init__.py +9 -2
- htmlgraph/analytics/cli.py +190 -51
- htmlgraph/analytics/cost_analyzer.py +391 -0
- htmlgraph/analytics/cost_monitor.py +664 -0
- htmlgraph/analytics/cost_reporter.py +675 -0
- htmlgraph/analytics/cross_session.py +617 -0
- htmlgraph/analytics/dependency.py +192 -100
- htmlgraph/analytics/pattern_learning.py +771 -0
- htmlgraph/analytics/session_graph.py +707 -0
- htmlgraph/analytics/strategic/__init__.py +80 -0
- htmlgraph/analytics/strategic/cost_optimizer.py +611 -0
- htmlgraph/analytics/strategic/pattern_detector.py +876 -0
- htmlgraph/analytics/strategic/preference_manager.py +709 -0
- htmlgraph/analytics/strategic/suggestion_engine.py +747 -0
- htmlgraph/analytics/work_type.py +190 -14
- htmlgraph/analytics_index.py +135 -51
- htmlgraph/api/__init__.py +3 -0
- htmlgraph/api/cost_alerts_websocket.py +416 -0
- htmlgraph/api/main.py +2498 -0
- htmlgraph/api/static/htmx.min.js +1 -0
- htmlgraph/api/static/style-redesign.css +1344 -0
- htmlgraph/api/static/style.css +1079 -0
- htmlgraph/api/templates/dashboard-redesign.html +1366 -0
- htmlgraph/api/templates/dashboard.html +794 -0
- htmlgraph/api/templates/partials/activity-feed-hierarchical.html +326 -0
- htmlgraph/api/templates/partials/activity-feed.html +1100 -0
- htmlgraph/api/templates/partials/agents-redesign.html +317 -0
- htmlgraph/api/templates/partials/agents.html +317 -0
- htmlgraph/api/templates/partials/event-traces.html +373 -0
- htmlgraph/api/templates/partials/features-kanban-redesign.html +509 -0
- htmlgraph/api/templates/partials/features.html +578 -0
- htmlgraph/api/templates/partials/metrics-redesign.html +346 -0
- htmlgraph/api/templates/partials/metrics.html +346 -0
- htmlgraph/api/templates/partials/orchestration-redesign.html +443 -0
- htmlgraph/api/templates/partials/orchestration.html +198 -0
- htmlgraph/api/templates/partials/spawners.html +375 -0
- htmlgraph/api/templates/partials/work-items.html +613 -0
- htmlgraph/api/websocket.py +538 -0
- htmlgraph/archive/__init__.py +24 -0
- htmlgraph/archive/bloom.py +234 -0
- htmlgraph/archive/fts.py +297 -0
- htmlgraph/archive/manager.py +583 -0
- htmlgraph/archive/search.py +244 -0
- htmlgraph/atomic_ops.py +560 -0
- htmlgraph/attribute_index.py +208 -0
- htmlgraph/bounded_paths.py +539 -0
- htmlgraph/builders/__init__.py +14 -0
- htmlgraph/builders/base.py +118 -29
- htmlgraph/builders/bug.py +150 -0
- htmlgraph/builders/chore.py +119 -0
- htmlgraph/builders/epic.py +150 -0
- htmlgraph/builders/feature.py +31 -6
- htmlgraph/builders/insight.py +195 -0
- htmlgraph/builders/metric.py +217 -0
- htmlgraph/builders/pattern.py +202 -0
- htmlgraph/builders/phase.py +162 -0
- htmlgraph/builders/spike.py +52 -19
- htmlgraph/builders/track.py +148 -72
- htmlgraph/cigs/__init__.py +81 -0
- htmlgraph/cigs/autonomy.py +385 -0
- htmlgraph/cigs/cost.py +475 -0
- htmlgraph/cigs/messages_basic.py +472 -0
- htmlgraph/cigs/messaging.py +365 -0
- htmlgraph/cigs/models.py +771 -0
- htmlgraph/cigs/pattern_storage.py +427 -0
- htmlgraph/cigs/patterns.py +503 -0
- htmlgraph/cigs/posttool_analyzer.py +234 -0
- htmlgraph/cigs/reporter.py +818 -0
- htmlgraph/cigs/tracker.py +317 -0
- htmlgraph/cli/.htmlgraph/.session-warning-state.json +6 -0
- htmlgraph/cli/.htmlgraph/agents.json +72 -0
- htmlgraph/cli/.htmlgraph/htmlgraph.db +0 -0
- htmlgraph/cli/__init__.py +42 -0
- htmlgraph/cli/__main__.py +6 -0
- htmlgraph/cli/analytics.py +1424 -0
- htmlgraph/cli/base.py +685 -0
- htmlgraph/cli/constants.py +206 -0
- htmlgraph/cli/core.py +954 -0
- htmlgraph/cli/main.py +147 -0
- htmlgraph/cli/models.py +475 -0
- htmlgraph/cli/templates/__init__.py +1 -0
- htmlgraph/cli/templates/cost_dashboard.py +399 -0
- htmlgraph/cli/work/__init__.py +239 -0
- htmlgraph/cli/work/browse.py +115 -0
- htmlgraph/cli/work/features.py +568 -0
- htmlgraph/cli/work/orchestration.py +676 -0
- htmlgraph/cli/work/report.py +728 -0
- htmlgraph/cli/work/sessions.py +466 -0
- htmlgraph/cli/work/snapshot.py +559 -0
- htmlgraph/cli/work/tracks.py +486 -0
- htmlgraph/cli_commands/__init__.py +1 -0
- htmlgraph/cli_commands/feature.py +195 -0
- htmlgraph/cli_framework.py +115 -0
- htmlgraph/collections/__init__.py +18 -0
- htmlgraph/collections/base.py +415 -98
- htmlgraph/collections/bug.py +53 -0
- htmlgraph/collections/chore.py +53 -0
- htmlgraph/collections/epic.py +53 -0
- htmlgraph/collections/feature.py +12 -26
- htmlgraph/collections/insight.py +100 -0
- htmlgraph/collections/metric.py +92 -0
- htmlgraph/collections/pattern.py +97 -0
- htmlgraph/collections/phase.py +53 -0
- htmlgraph/collections/session.py +194 -0
- htmlgraph/collections/spike.py +56 -16
- htmlgraph/collections/task_delegation.py +241 -0
- htmlgraph/collections/todo.py +511 -0
- htmlgraph/collections/traces.py +487 -0
- htmlgraph/config/cost_models.json +56 -0
- htmlgraph/config.py +190 -0
- htmlgraph/context_analytics.py +344 -0
- htmlgraph/converter.py +216 -28
- htmlgraph/cost_analysis/__init__.py +5 -0
- htmlgraph/cost_analysis/analyzer.py +438 -0
- htmlgraph/dashboard.html +2406 -307
- htmlgraph/dashboard.html.backup +6592 -0
- htmlgraph/dashboard.html.bak +7181 -0
- htmlgraph/dashboard.html.bak2 +7231 -0
- htmlgraph/dashboard.html.bak3 +7232 -0
- htmlgraph/db/__init__.py +38 -0
- htmlgraph/db/queries.py +790 -0
- htmlgraph/db/schema.py +1788 -0
- htmlgraph/decorators.py +317 -0
- htmlgraph/dependency_models.py +19 -2
- htmlgraph/deploy.py +142 -125
- htmlgraph/deployment_models.py +474 -0
- htmlgraph/docs/API_REFERENCE.md +841 -0
- htmlgraph/docs/HTTP_API.md +750 -0
- htmlgraph/docs/INTEGRATION_GUIDE.md +752 -0
- htmlgraph/docs/ORCHESTRATION_PATTERNS.md +717 -0
- htmlgraph/docs/README.md +532 -0
- htmlgraph/docs/__init__.py +77 -0
- htmlgraph/docs/docs_version.py +55 -0
- htmlgraph/docs/metadata.py +93 -0
- htmlgraph/docs/migrations.py +232 -0
- htmlgraph/docs/template_engine.py +143 -0
- htmlgraph/docs/templates/_sections/cli_reference.md.j2 +52 -0
- htmlgraph/docs/templates/_sections/core_concepts.md.j2 +29 -0
- htmlgraph/docs/templates/_sections/sdk_basics.md.j2 +69 -0
- htmlgraph/docs/templates/base_agents.md.j2 +78 -0
- htmlgraph/docs/templates/example_user_override.md.j2 +47 -0
- htmlgraph/docs/version_check.py +163 -0
- htmlgraph/edge_index.py +182 -27
- htmlgraph/error_handler.py +544 -0
- htmlgraph/event_log.py +100 -52
- htmlgraph/event_migration.py +13 -4
- htmlgraph/exceptions.py +49 -0
- htmlgraph/file_watcher.py +101 -28
- htmlgraph/find_api.py +75 -63
- htmlgraph/git_events.py +145 -63
- htmlgraph/graph.py +1122 -106
- htmlgraph/hooks/.htmlgraph/.session-warning-state.json +6 -0
- htmlgraph/hooks/.htmlgraph/agents.json +72 -0
- htmlgraph/hooks/.htmlgraph/index.sqlite +0 -0
- htmlgraph/hooks/__init__.py +45 -0
- htmlgraph/hooks/bootstrap.py +169 -0
- htmlgraph/hooks/cigs_pretool_enforcer.py +354 -0
- htmlgraph/hooks/concurrent_sessions.py +208 -0
- htmlgraph/hooks/context.py +350 -0
- htmlgraph/hooks/drift_handler.py +525 -0
- htmlgraph/hooks/event_tracker.py +1314 -0
- htmlgraph/hooks/git_commands.py +175 -0
- htmlgraph/hooks/hooks-config.example.json +12 -0
- htmlgraph/hooks/installer.py +343 -0
- htmlgraph/hooks/orchestrator.py +674 -0
- htmlgraph/hooks/orchestrator_reflector.py +223 -0
- htmlgraph/hooks/post-checkout.sh +28 -0
- htmlgraph/hooks/post-commit.sh +24 -0
- htmlgraph/hooks/post-merge.sh +26 -0
- htmlgraph/hooks/post_tool_use_failure.py +273 -0
- htmlgraph/hooks/post_tool_use_handler.py +257 -0
- htmlgraph/hooks/posttooluse.py +408 -0
- htmlgraph/hooks/pre-commit.sh +94 -0
- htmlgraph/hooks/pre-push.sh +28 -0
- htmlgraph/hooks/pretooluse.py +819 -0
- htmlgraph/hooks/prompt_analyzer.py +637 -0
- htmlgraph/hooks/session_handler.py +668 -0
- htmlgraph/hooks/session_summary.py +395 -0
- htmlgraph/hooks/state_manager.py +504 -0
- htmlgraph/hooks/subagent_detection.py +202 -0
- htmlgraph/hooks/subagent_stop.py +369 -0
- htmlgraph/hooks/task_enforcer.py +255 -0
- htmlgraph/hooks/task_validator.py +177 -0
- htmlgraph/hooks/validator.py +628 -0
- htmlgraph/ids.py +41 -27
- htmlgraph/index.d.ts +286 -0
- htmlgraph/learning.py +767 -0
- htmlgraph/mcp_server.py +69 -23
- htmlgraph/models.py +1586 -87
- htmlgraph/operations/README.md +62 -0
- htmlgraph/operations/__init__.py +79 -0
- htmlgraph/operations/analytics.py +339 -0
- htmlgraph/operations/bootstrap.py +289 -0
- htmlgraph/operations/events.py +244 -0
- htmlgraph/operations/fastapi_server.py +231 -0
- htmlgraph/operations/hooks.py +350 -0
- htmlgraph/operations/initialization.py +597 -0
- htmlgraph/operations/initialization.py.backup +228 -0
- htmlgraph/operations/server.py +303 -0
- htmlgraph/orchestration/__init__.py +58 -0
- htmlgraph/orchestration/claude_launcher.py +179 -0
- htmlgraph/orchestration/command_builder.py +72 -0
- htmlgraph/orchestration/headless_spawner.py +281 -0
- htmlgraph/orchestration/live_events.py +377 -0
- htmlgraph/orchestration/model_selection.py +327 -0
- htmlgraph/orchestration/plugin_manager.py +140 -0
- htmlgraph/orchestration/prompts.py +137 -0
- htmlgraph/orchestration/spawner_event_tracker.py +383 -0
- htmlgraph/orchestration/spawners/__init__.py +16 -0
- htmlgraph/orchestration/spawners/base.py +194 -0
- htmlgraph/orchestration/spawners/claude.py +173 -0
- htmlgraph/orchestration/spawners/codex.py +435 -0
- htmlgraph/orchestration/spawners/copilot.py +294 -0
- htmlgraph/orchestration/spawners/gemini.py +471 -0
- htmlgraph/orchestration/subprocess_runner.py +36 -0
- htmlgraph/orchestration/task_coordination.py +343 -0
- htmlgraph/orchestration.md +563 -0
- htmlgraph/orchestrator-system-prompt-optimized.txt +863 -0
- htmlgraph/orchestrator.py +669 -0
- htmlgraph/orchestrator_config.py +357 -0
- htmlgraph/orchestrator_mode.py +328 -0
- htmlgraph/orchestrator_validator.py +133 -0
- htmlgraph/parallel.py +646 -0
- htmlgraph/parser.py +160 -35
- htmlgraph/path_query.py +608 -0
- htmlgraph/pattern_matcher.py +636 -0
- htmlgraph/planning.py +147 -52
- htmlgraph/pydantic_models.py +476 -0
- htmlgraph/quality_gates.py +350 -0
- htmlgraph/query_builder.py +109 -72
- htmlgraph/query_composer.py +509 -0
- htmlgraph/reflection.py +443 -0
- htmlgraph/refs.py +344 -0
- htmlgraph/repo_hash.py +512 -0
- htmlgraph/repositories/__init__.py +292 -0
- htmlgraph/repositories/analytics_repository.py +455 -0
- htmlgraph/repositories/analytics_repository_standard.py +628 -0
- htmlgraph/repositories/feature_repository.py +581 -0
- htmlgraph/repositories/feature_repository_htmlfile.py +668 -0
- htmlgraph/repositories/feature_repository_memory.py +607 -0
- htmlgraph/repositories/feature_repository_sqlite.py +858 -0
- htmlgraph/repositories/filter_service.py +620 -0
- htmlgraph/repositories/filter_service_standard.py +445 -0
- htmlgraph/repositories/shared_cache.py +621 -0
- htmlgraph/repositories/shared_cache_memory.py +395 -0
- htmlgraph/repositories/track_repository.py +552 -0
- htmlgraph/repositories/track_repository_htmlfile.py +619 -0
- htmlgraph/repositories/track_repository_memory.py +508 -0
- htmlgraph/repositories/track_repository_sqlite.py +711 -0
- htmlgraph/routing.py +8 -19
- htmlgraph/scripts/deploy.py +1 -2
- htmlgraph/sdk/__init__.py +398 -0
- htmlgraph/sdk/__init__.pyi +14 -0
- htmlgraph/sdk/analytics/__init__.py +19 -0
- htmlgraph/sdk/analytics/engine.py +155 -0
- htmlgraph/sdk/analytics/helpers.py +178 -0
- htmlgraph/sdk/analytics/registry.py +109 -0
- htmlgraph/sdk/base.py +484 -0
- htmlgraph/sdk/constants.py +216 -0
- htmlgraph/sdk/core.pyi +308 -0
- htmlgraph/sdk/discovery.py +120 -0
- htmlgraph/sdk/help/__init__.py +12 -0
- htmlgraph/sdk/help/mixin.py +699 -0
- htmlgraph/sdk/mixins/__init__.py +15 -0
- htmlgraph/sdk/mixins/attribution.py +113 -0
- htmlgraph/sdk/mixins/mixin.py +410 -0
- htmlgraph/sdk/operations/__init__.py +12 -0
- htmlgraph/sdk/operations/mixin.py +427 -0
- htmlgraph/sdk/orchestration/__init__.py +17 -0
- htmlgraph/sdk/orchestration/coordinator.py +203 -0
- htmlgraph/sdk/orchestration/spawner.py +204 -0
- htmlgraph/sdk/planning/__init__.py +19 -0
- htmlgraph/sdk/planning/bottlenecks.py +93 -0
- htmlgraph/sdk/planning/mixin.py +211 -0
- htmlgraph/sdk/planning/parallel.py +186 -0
- htmlgraph/sdk/planning/queue.py +210 -0
- htmlgraph/sdk/planning/recommendations.py +87 -0
- htmlgraph/sdk/planning/smart_planning.py +319 -0
- htmlgraph/sdk/session/__init__.py +19 -0
- htmlgraph/sdk/session/continuity.py +57 -0
- htmlgraph/sdk/session/handoff.py +110 -0
- htmlgraph/sdk/session/info.py +309 -0
- htmlgraph/sdk/session/manager.py +103 -0
- htmlgraph/sdk/strategic/__init__.py +26 -0
- htmlgraph/sdk/strategic/mixin.py +563 -0
- htmlgraph/server.py +685 -180
- htmlgraph/services/__init__.py +10 -0
- htmlgraph/services/claiming.py +199 -0
- htmlgraph/session_hooks.py +300 -0
- htmlgraph/session_manager.py +1392 -175
- htmlgraph/session_registry.py +587 -0
- htmlgraph/session_state.py +436 -0
- htmlgraph/session_warning.py +201 -0
- htmlgraph/sessions/__init__.py +23 -0
- htmlgraph/sessions/handoff.py +756 -0
- htmlgraph/setup.py +34 -17
- htmlgraph/spike_index.py +143 -0
- htmlgraph/sync_docs.py +12 -15
- htmlgraph/system_prompts.py +450 -0
- htmlgraph/templates/AGENTS.md.template +366 -0
- htmlgraph/templates/CLAUDE.md.template +97 -0
- htmlgraph/templates/GEMINI.md.template +87 -0
- htmlgraph/templates/orchestration-view.html +350 -0
- htmlgraph/track_builder.py +146 -15
- htmlgraph/track_manager.py +69 -21
- htmlgraph/transcript.py +890 -0
- htmlgraph/transcript_analytics.py +699 -0
- htmlgraph/types.py +323 -0
- htmlgraph/validation.py +115 -0
- htmlgraph/watch.py +8 -5
- htmlgraph/work_type_utils.py +3 -2
- {htmlgraph-0.9.3.data → htmlgraph-0.27.5.data}/data/htmlgraph/dashboard.html +2406 -307
- htmlgraph-0.27.5.data/data/htmlgraph/templates/AGENTS.md.template +366 -0
- htmlgraph-0.27.5.data/data/htmlgraph/templates/CLAUDE.md.template +97 -0
- htmlgraph-0.27.5.data/data/htmlgraph/templates/GEMINI.md.template +87 -0
- {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/METADATA +97 -64
- htmlgraph-0.27.5.dist-info/RECORD +337 -0
- {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/entry_points.txt +1 -1
- htmlgraph/cli.py +0 -2688
- htmlgraph/sdk.py +0 -709
- htmlgraph-0.9.3.dist-info/RECORD +0 -61
- {htmlgraph-0.9.3.data → htmlgraph-0.27.5.data}/data/htmlgraph/styles.css +0 -0
- {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pydantic models for CLI input validation.
|
|
3
|
+
|
|
4
|
+
This module provides type-safe validation for all CLI commands using Pydantic v2.
|
|
5
|
+
Models ensure data integrity before being passed to SDK operations.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Literal
|
|
9
|
+
|
|
10
|
+
from pydantic import BaseModel, Field, field_validator
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class CLIInputBase(BaseModel):
|
|
14
|
+
"""Base class for all CLI input models with common configuration."""
|
|
15
|
+
|
|
16
|
+
class Config:
|
|
17
|
+
extra = "forbid" # No extra fields allowed
|
|
18
|
+
str_strip_whitespace = True
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# =============================================================================
|
|
22
|
+
# Feature Commands
|
|
23
|
+
# =============================================================================
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class FeatureCreateInput(CLIInputBase):
|
|
27
|
+
"""Input model for 'feature create' command."""
|
|
28
|
+
|
|
29
|
+
title: str = Field(..., min_length=1, max_length=200, description="Feature title")
|
|
30
|
+
description: str | None = Field(
|
|
31
|
+
default=None, max_length=1000, description="Feature description"
|
|
32
|
+
)
|
|
33
|
+
priority: Literal["low", "medium", "high"] = Field(
|
|
34
|
+
default="medium", description="Feature priority level"
|
|
35
|
+
)
|
|
36
|
+
steps: int | None = Field(
|
|
37
|
+
default=None, ge=1, le=50, description="Number of implementation steps"
|
|
38
|
+
)
|
|
39
|
+
collection: str = Field(
|
|
40
|
+
default="features", description="Collection name (features, bugs, etc.)"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
@field_validator("title")
|
|
44
|
+
@classmethod
|
|
45
|
+
def validate_title(cls, v: str) -> str:
|
|
46
|
+
"""Ensure title is not empty or whitespace only."""
|
|
47
|
+
if not v.strip():
|
|
48
|
+
raise ValueError("Title cannot be empty or whitespace only")
|
|
49
|
+
return v.strip()
|
|
50
|
+
|
|
51
|
+
@field_validator("description")
|
|
52
|
+
@classmethod
|
|
53
|
+
def validate_description(cls, v: str | None) -> str | None:
|
|
54
|
+
"""Ensure description is stripped if provided."""
|
|
55
|
+
if v is not None:
|
|
56
|
+
v = v.strip()
|
|
57
|
+
if not v:
|
|
58
|
+
return None
|
|
59
|
+
return v
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class FeatureStartInput(CLIInputBase):
|
|
63
|
+
"""Input model for 'feature start' command."""
|
|
64
|
+
|
|
65
|
+
feature_id: str = Field(..., min_length=1, description="Feature ID to start")
|
|
66
|
+
collection: str = Field(default="features", description="Collection name")
|
|
67
|
+
|
|
68
|
+
@field_validator("feature_id")
|
|
69
|
+
@classmethod
|
|
70
|
+
def validate_feature_id(cls, v: str) -> str:
|
|
71
|
+
"""Ensure feature ID is not empty."""
|
|
72
|
+
if not v.strip():
|
|
73
|
+
raise ValueError("Feature ID cannot be empty")
|
|
74
|
+
return v.strip()
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class FeatureCompleteInput(CLIInputBase):
|
|
78
|
+
"""Input model for 'feature complete' command."""
|
|
79
|
+
|
|
80
|
+
feature_id: str = Field(..., min_length=1, description="Feature ID to complete")
|
|
81
|
+
collection: str = Field(default="features", description="Collection name")
|
|
82
|
+
|
|
83
|
+
@field_validator("feature_id")
|
|
84
|
+
@classmethod
|
|
85
|
+
def validate_feature_id(cls, v: str) -> str:
|
|
86
|
+
"""Ensure feature ID is not empty."""
|
|
87
|
+
if not v.strip():
|
|
88
|
+
raise ValueError("Feature ID cannot be empty")
|
|
89
|
+
return v.strip()
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class FeaturePrimaryInput(CLIInputBase):
|
|
93
|
+
"""Input model for 'feature primary' command."""
|
|
94
|
+
|
|
95
|
+
feature_id: str = Field(
|
|
96
|
+
..., min_length=1, description="Feature ID to set as primary"
|
|
97
|
+
)
|
|
98
|
+
collection: str = Field(default="features", description="Collection name")
|
|
99
|
+
|
|
100
|
+
@field_validator("feature_id")
|
|
101
|
+
@classmethod
|
|
102
|
+
def validate_feature_id(cls, v: str) -> str:
|
|
103
|
+
"""Ensure feature ID is not empty."""
|
|
104
|
+
if not v.strip():
|
|
105
|
+
raise ValueError("Feature ID cannot be empty")
|
|
106
|
+
return v.strip()
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class FeatureClaimInput(CLIInputBase):
|
|
110
|
+
"""Input model for 'feature claim' command."""
|
|
111
|
+
|
|
112
|
+
feature_id: str = Field(..., min_length=1, description="Feature ID to claim")
|
|
113
|
+
collection: str = Field(default="features", description="Collection name")
|
|
114
|
+
|
|
115
|
+
@field_validator("feature_id")
|
|
116
|
+
@classmethod
|
|
117
|
+
def validate_feature_id(cls, v: str) -> str:
|
|
118
|
+
"""Ensure feature ID is not empty."""
|
|
119
|
+
if not v.strip():
|
|
120
|
+
raise ValueError("Feature ID cannot be empty")
|
|
121
|
+
return v.strip()
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class FeatureReleaseInput(CLIInputBase):
|
|
125
|
+
"""Input model for 'feature release' command."""
|
|
126
|
+
|
|
127
|
+
feature_id: str = Field(..., min_length=1, description="Feature ID to release")
|
|
128
|
+
collection: str = Field(default="features", description="Collection name")
|
|
129
|
+
|
|
130
|
+
@field_validator("feature_id")
|
|
131
|
+
@classmethod
|
|
132
|
+
def validate_feature_id(cls, v: str) -> str:
|
|
133
|
+
"""Ensure feature ID is not empty."""
|
|
134
|
+
if not v.strip():
|
|
135
|
+
raise ValueError("Feature ID cannot be empty")
|
|
136
|
+
return v.strip()
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
# =============================================================================
|
|
140
|
+
# Session Commands
|
|
141
|
+
# =============================================================================
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class SessionStartInput(CLIInputBase):
|
|
145
|
+
"""Input model for 'session start' command."""
|
|
146
|
+
|
|
147
|
+
session_id: str | None = Field(
|
|
148
|
+
default=None, description="Optional custom session ID"
|
|
149
|
+
)
|
|
150
|
+
title: str | None = Field(default=None, max_length=500, description="Session title")
|
|
151
|
+
agent: str | None = Field(default=None, description="Agent name")
|
|
152
|
+
|
|
153
|
+
@field_validator("session_id")
|
|
154
|
+
@classmethod
|
|
155
|
+
def validate_session_id(cls, v: str | None) -> str | None:
|
|
156
|
+
"""Ensure session ID is not empty if provided."""
|
|
157
|
+
if v is not None and not v.strip():
|
|
158
|
+
raise ValueError("Session ID cannot be empty")
|
|
159
|
+
return v.strip() if v else None
|
|
160
|
+
|
|
161
|
+
@field_validator("title")
|
|
162
|
+
@classmethod
|
|
163
|
+
def validate_title(cls, v: str | None) -> str | None:
|
|
164
|
+
"""Ensure title is stripped if provided."""
|
|
165
|
+
if v is not None:
|
|
166
|
+
v = v.strip()
|
|
167
|
+
if not v:
|
|
168
|
+
return None
|
|
169
|
+
return v
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class SessionEndInput(CLIInputBase):
|
|
173
|
+
"""Input model for 'session end' command."""
|
|
174
|
+
|
|
175
|
+
session_id: str = Field(..., min_length=1, description="Session ID to end")
|
|
176
|
+
notes: str | None = Field(
|
|
177
|
+
default=None, max_length=2000, description="Handoff notes"
|
|
178
|
+
)
|
|
179
|
+
recommend: str | None = Field(
|
|
180
|
+
default=None, max_length=500, description="Recommended next steps"
|
|
181
|
+
)
|
|
182
|
+
blocker: list[str] | None = Field(default=None, description="List of blockers")
|
|
183
|
+
|
|
184
|
+
@field_validator("session_id")
|
|
185
|
+
@classmethod
|
|
186
|
+
def validate_session_id(cls, v: str) -> str:
|
|
187
|
+
"""Ensure session ID is not empty."""
|
|
188
|
+
if not v.strip():
|
|
189
|
+
raise ValueError("Session ID cannot be empty")
|
|
190
|
+
return v.strip()
|
|
191
|
+
|
|
192
|
+
@field_validator("notes")
|
|
193
|
+
@classmethod
|
|
194
|
+
def validate_notes(cls, v: str | None) -> str | None:
|
|
195
|
+
"""Ensure notes are stripped if provided."""
|
|
196
|
+
if v is not None:
|
|
197
|
+
v = v.strip()
|
|
198
|
+
if not v:
|
|
199
|
+
return None
|
|
200
|
+
return v
|
|
201
|
+
|
|
202
|
+
@field_validator("recommend")
|
|
203
|
+
@classmethod
|
|
204
|
+
def validate_recommend(cls, v: str | None) -> str | None:
|
|
205
|
+
"""Ensure recommendation is stripped if provided."""
|
|
206
|
+
if v is not None:
|
|
207
|
+
v = v.strip()
|
|
208
|
+
if not v:
|
|
209
|
+
return None
|
|
210
|
+
return v
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class SessionHandoffInput(CLIInputBase):
|
|
214
|
+
"""Input model for 'session handoff' command."""
|
|
215
|
+
|
|
216
|
+
session_id: str | None = Field(default=None, description="Session ID for handoff")
|
|
217
|
+
notes: str | None = Field(
|
|
218
|
+
default=None, max_length=2000, description="Handoff notes"
|
|
219
|
+
)
|
|
220
|
+
recommend: str | None = Field(
|
|
221
|
+
default=None, max_length=500, description="Recommended next steps"
|
|
222
|
+
)
|
|
223
|
+
blocker: list[str] | None = Field(default=None, description="List of blockers")
|
|
224
|
+
show: bool = Field(default=False, description="Show current handoff context")
|
|
225
|
+
|
|
226
|
+
@field_validator("session_id")
|
|
227
|
+
@classmethod
|
|
228
|
+
def validate_session_id(cls, v: str | None) -> str | None:
|
|
229
|
+
"""Ensure session ID is not empty if provided."""
|
|
230
|
+
if v is not None and not v.strip():
|
|
231
|
+
raise ValueError("Session ID cannot be empty")
|
|
232
|
+
return v.strip() if v else None
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class SessionListInput(CLIInputBase):
|
|
236
|
+
"""Input model for 'session list' command."""
|
|
237
|
+
|
|
238
|
+
status: Literal["active", "ended"] | None = Field(
|
|
239
|
+
default=None, description="Filter by session status"
|
|
240
|
+
)
|
|
241
|
+
limit: int = Field(
|
|
242
|
+
default=20, ge=1, le=100, description="Maximum results to return"
|
|
243
|
+
)
|
|
244
|
+
offset: int = Field(default=0, ge=0, description="Result offset for pagination")
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
# =============================================================================
|
|
248
|
+
# Track/Activity Commands
|
|
249
|
+
# =============================================================================
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
class ActivityTrackInput(CLIInputBase):
|
|
253
|
+
"""Input model for 'activity track' command."""
|
|
254
|
+
|
|
255
|
+
tool: str = Field(
|
|
256
|
+
...,
|
|
257
|
+
min_length=1,
|
|
258
|
+
max_length=100,
|
|
259
|
+
description="Tool name (e.g., 'Bash', 'Read')",
|
|
260
|
+
)
|
|
261
|
+
summary: str = Field(
|
|
262
|
+
..., min_length=1, max_length=500, description="Activity summary"
|
|
263
|
+
)
|
|
264
|
+
files: list[str] | None = Field(
|
|
265
|
+
default=None, description="Files involved in the activity"
|
|
266
|
+
)
|
|
267
|
+
session: str | None = Field(
|
|
268
|
+
default=None, description="Session ID (auto-detected if not provided)"
|
|
269
|
+
)
|
|
270
|
+
failed: bool = Field(default=False, description="Mark as failed")
|
|
271
|
+
|
|
272
|
+
@field_validator("tool")
|
|
273
|
+
@classmethod
|
|
274
|
+
def validate_tool(cls, v: str) -> str:
|
|
275
|
+
"""Ensure tool name is stripped and valid."""
|
|
276
|
+
if not v.strip():
|
|
277
|
+
raise ValueError("Tool name cannot be empty")
|
|
278
|
+
return v.strip()
|
|
279
|
+
|
|
280
|
+
@field_validator("summary")
|
|
281
|
+
@classmethod
|
|
282
|
+
def validate_summary(cls, v: str) -> str:
|
|
283
|
+
"""Ensure summary is stripped and not empty."""
|
|
284
|
+
if not v.strip():
|
|
285
|
+
raise ValueError("Summary cannot be empty")
|
|
286
|
+
return v.strip()
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
# =============================================================================
|
|
290
|
+
# Spike Commands
|
|
291
|
+
# =============================================================================
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
class SpikeCreateInput(CLIInputBase):
|
|
295
|
+
"""Input model for 'spike create' command."""
|
|
296
|
+
|
|
297
|
+
title: str = Field(..., min_length=1, max_length=200, description="Spike title")
|
|
298
|
+
findings: str | None = Field(
|
|
299
|
+
default=None, max_length=5000, description="Spike findings"
|
|
300
|
+
)
|
|
301
|
+
priority: Literal["low", "medium", "high"] = Field(
|
|
302
|
+
default="medium", description="Spike priority"
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
@field_validator("title")
|
|
306
|
+
@classmethod
|
|
307
|
+
def validate_title(cls, v: str) -> str:
|
|
308
|
+
"""Ensure title is not empty."""
|
|
309
|
+
if not v.strip():
|
|
310
|
+
raise ValueError("Title cannot be empty or whitespace only")
|
|
311
|
+
return v.strip()
|
|
312
|
+
|
|
313
|
+
@field_validator("findings")
|
|
314
|
+
@classmethod
|
|
315
|
+
def validate_findings(cls, v: str | None) -> str | None:
|
|
316
|
+
"""Ensure findings are stripped if provided."""
|
|
317
|
+
if v is not None:
|
|
318
|
+
v = v.strip()
|
|
319
|
+
if not v:
|
|
320
|
+
return None
|
|
321
|
+
return v
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
# =============================================================================
|
|
325
|
+
# Documentation Commands
|
|
326
|
+
# =============================================================================
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
class DocsGenerateInput(CLIInputBase):
|
|
330
|
+
"""Input model for 'docs generate' command."""
|
|
331
|
+
|
|
332
|
+
output_dir: str | None = Field(
|
|
333
|
+
default=None, description="Output directory for generated docs"
|
|
334
|
+
)
|
|
335
|
+
format: Literal["markdown", "html"] = Field(
|
|
336
|
+
default="markdown", description="Output format"
|
|
337
|
+
)
|
|
338
|
+
include_api: bool = Field(default=True, description="Include API documentation")
|
|
339
|
+
include_examples: bool = Field(default=True, description="Include usage examples")
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
# =============================================================================
|
|
343
|
+
# Track Planning Commands (NEW)
|
|
344
|
+
# =============================================================================
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
class TrackCreateInput(CLIInputBase):
|
|
348
|
+
"""Input model for 'track create' command."""
|
|
349
|
+
|
|
350
|
+
title: str = Field(..., min_length=1, max_length=200, description="Track title")
|
|
351
|
+
priority: Literal["low", "medium", "high"] = Field(
|
|
352
|
+
default="medium", description="Track priority"
|
|
353
|
+
)
|
|
354
|
+
description: str | None = Field(
|
|
355
|
+
default=None, max_length=1000, description="Track description"
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
@field_validator("title")
|
|
359
|
+
@classmethod
|
|
360
|
+
def validate_title(cls, v: str) -> str:
|
|
361
|
+
"""Ensure title is not empty."""
|
|
362
|
+
if not v.strip():
|
|
363
|
+
raise ValueError("Title cannot be empty or whitespace only")
|
|
364
|
+
return v.strip()
|
|
365
|
+
|
|
366
|
+
@field_validator("description")
|
|
367
|
+
@classmethod
|
|
368
|
+
def validate_description(cls, v: str | None) -> str | None:
|
|
369
|
+
"""Ensure description is stripped if provided."""
|
|
370
|
+
if v is not None:
|
|
371
|
+
v = v.strip()
|
|
372
|
+
if not v:
|
|
373
|
+
return None
|
|
374
|
+
return v
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
class TrackSpecInput(CLIInputBase):
|
|
378
|
+
"""Input model for 'track spec' command."""
|
|
379
|
+
|
|
380
|
+
track_id: str = Field(..., min_length=1, description="Track ID")
|
|
381
|
+
title: str = Field(..., min_length=1, max_length=200, description="Spec title")
|
|
382
|
+
content: str | None = Field(
|
|
383
|
+
default=None, max_length=5000, description="Spec content"
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
@field_validator("track_id")
|
|
387
|
+
@classmethod
|
|
388
|
+
def validate_track_id(cls, v: str) -> str:
|
|
389
|
+
"""Ensure track ID is not empty."""
|
|
390
|
+
if not v.strip():
|
|
391
|
+
raise ValueError("Track ID cannot be empty")
|
|
392
|
+
return v.strip()
|
|
393
|
+
|
|
394
|
+
@field_validator("title")
|
|
395
|
+
@classmethod
|
|
396
|
+
def validate_title(cls, v: str) -> str:
|
|
397
|
+
"""Ensure title is not empty."""
|
|
398
|
+
if not v.strip():
|
|
399
|
+
raise ValueError("Title cannot be empty")
|
|
400
|
+
return v.strip()
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
class TrackPlanInput(CLIInputBase):
|
|
404
|
+
"""Input model for 'track plan' command."""
|
|
405
|
+
|
|
406
|
+
track_id: str = Field(..., min_length=1, description="Track ID")
|
|
407
|
+
title: str = Field(..., min_length=1, max_length=200, description="Plan title")
|
|
408
|
+
content: str | None = Field(
|
|
409
|
+
default=None, max_length=5000, description="Plan content"
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
@field_validator("track_id")
|
|
413
|
+
@classmethod
|
|
414
|
+
def validate_track_id(cls, v: str) -> str:
|
|
415
|
+
"""Ensure track ID is not empty."""
|
|
416
|
+
if not v.strip():
|
|
417
|
+
raise ValueError("Track ID cannot be empty")
|
|
418
|
+
return v.strip()
|
|
419
|
+
|
|
420
|
+
@field_validator("title")
|
|
421
|
+
@classmethod
|
|
422
|
+
def validate_title(cls, v: str) -> str:
|
|
423
|
+
"""Ensure title is not empty."""
|
|
424
|
+
if not v.strip():
|
|
425
|
+
raise ValueError("Title cannot be empty")
|
|
426
|
+
return v.strip()
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
class TrackDeleteInput(CLIInputBase):
|
|
430
|
+
"""Input model for 'track delete' command."""
|
|
431
|
+
|
|
432
|
+
track_id: str = Field(..., min_length=1, description="Track ID to delete")
|
|
433
|
+
force: bool = Field(
|
|
434
|
+
default=False, description="Force deletion without confirmation"
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
@field_validator("track_id")
|
|
438
|
+
@classmethod
|
|
439
|
+
def validate_track_id(cls, v: str) -> str:
|
|
440
|
+
"""Ensure track ID is not empty."""
|
|
441
|
+
if not v.strip():
|
|
442
|
+
raise ValueError("Track ID cannot be empty")
|
|
443
|
+
return v.strip()
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
# =============================================================================
|
|
447
|
+
# Archive Commands
|
|
448
|
+
# =============================================================================
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
class ArchiveCreateInput(CLIInputBase):
|
|
452
|
+
"""Input model for 'archive create' command."""
|
|
453
|
+
|
|
454
|
+
title: str = Field(..., min_length=1, max_length=200, description="Archive title")
|
|
455
|
+
items: list[str] | None = Field(default=None, description="Items to archive")
|
|
456
|
+
description: str | None = Field(
|
|
457
|
+
default=None, max_length=1000, description="Archive description"
|
|
458
|
+
)
|
|
459
|
+
|
|
460
|
+
@field_validator("title")
|
|
461
|
+
@classmethod
|
|
462
|
+
def validate_title(cls, v: str) -> str:
|
|
463
|
+
"""Ensure title is not empty."""
|
|
464
|
+
if not v.strip():
|
|
465
|
+
raise ValueError("Title cannot be empty or whitespace only")
|
|
466
|
+
return v.strip()
|
|
467
|
+
|
|
468
|
+
@field_validator("description")
|
|
469
|
+
@classmethod
|
|
470
|
+
def validate_description(cls, v: str | None) -> str | None:
|
|
471
|
+
"""Ensure description is stripped if provided."""
|
|
472
|
+
if v is not None:
|
|
473
|
+
v = v.strip()
|
|
474
|
+
if not v:
|
|
475
|
+
return None
|
|
476
|
+
return v
|