htmlgraph 0.20.1__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 +51 -1
- htmlgraph/__init__.pyi +123 -0
- htmlgraph/agent_detection.py +26 -10
- htmlgraph/agent_registry.py +2 -1
- htmlgraph/analytics/__init__.py +8 -1
- htmlgraph/analytics/cli.py +86 -20
- 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 +10 -6
- 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 +67 -27
- htmlgraph/analytics_index.py +53 -20
- 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 +2 -1
- htmlgraph/bounded_paths.py +539 -0
- htmlgraph/builders/base.py +57 -2
- htmlgraph/builders/bug.py +19 -3
- htmlgraph/builders/chore.py +19 -3
- htmlgraph/builders/epic.py +19 -3
- htmlgraph/builders/feature.py +27 -3
- htmlgraph/builders/insight.py +2 -1
- htmlgraph/builders/metric.py +2 -1
- htmlgraph/builders/pattern.py +2 -1
- htmlgraph/builders/phase.py +19 -3
- htmlgraph/builders/spike.py +29 -3
- htmlgraph/builders/track.py +42 -1
- 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 +2 -0
- htmlgraph/collections/base.py +197 -14
- htmlgraph/collections/bug.py +2 -1
- htmlgraph/collections/chore.py +2 -1
- htmlgraph/collections/epic.py +2 -1
- htmlgraph/collections/feature.py +2 -1
- htmlgraph/collections/insight.py +2 -1
- htmlgraph/collections/metric.py +2 -1
- htmlgraph/collections/pattern.py +2 -1
- htmlgraph/collections/phase.py +2 -1
- htmlgraph/collections/session.py +194 -0
- htmlgraph/collections/spike.py +13 -2
- htmlgraph/collections/task_delegation.py +241 -0
- htmlgraph/collections/todo.py +14 -1
- htmlgraph/collections/traces.py +487 -0
- htmlgraph/config/cost_models.json +56 -0
- htmlgraph/config.py +190 -0
- htmlgraph/context_analytics.py +2 -1
- htmlgraph/converter.py +116 -7
- htmlgraph/cost_analysis/__init__.py +5 -0
- htmlgraph/cost_analysis/analyzer.py +438 -0
- htmlgraph/dashboard.html +2246 -248
- 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 +2 -1
- htmlgraph/deploy.py +26 -27
- 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 +2 -1
- htmlgraph/error_handler.py +544 -0
- htmlgraph/event_log.py +86 -37
- htmlgraph/event_migration.py +2 -1
- htmlgraph/file_watcher.py +12 -8
- htmlgraph/find_api.py +2 -1
- htmlgraph/git_events.py +67 -9
- 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 +8 -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 +790 -99
- htmlgraph/hooks/git_commands.py +175 -0
- htmlgraph/hooks/installer.py +5 -1
- htmlgraph/hooks/orchestrator.py +327 -76
- htmlgraph/hooks/orchestrator_reflector.py +31 -4
- htmlgraph/hooks/post_tool_use_failure.py +32 -7
- htmlgraph/hooks/post_tool_use_handler.py +257 -0
- htmlgraph/hooks/posttooluse.py +92 -19
- htmlgraph/hooks/pretooluse.py +527 -7
- 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 +99 -4
- htmlgraph/hooks/validator.py +212 -91
- htmlgraph/ids.py +2 -1
- htmlgraph/learning.py +125 -100
- htmlgraph/mcp_server.py +2 -1
- htmlgraph/models.py +217 -18
- 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.py → orchestration/task_coordination.py} +16 -8
- htmlgraph/orchestration.md +563 -0
- htmlgraph/orchestrator-system-prompt-optimized.txt +863 -0
- htmlgraph/orchestrator.py +2 -1
- htmlgraph/orchestrator_config.py +357 -0
- htmlgraph/orchestrator_mode.py +115 -4
- htmlgraph/parallel.py +2 -1
- htmlgraph/parser.py +86 -6
- htmlgraph/path_query.py +608 -0
- htmlgraph/pattern_matcher.py +636 -0
- htmlgraph/pydantic_models.py +476 -0
- htmlgraph/quality_gates.py +350 -0
- htmlgraph/query_builder.py +2 -1
- 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/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 +295 -107
- htmlgraph/session_hooks.py +300 -0
- htmlgraph/session_manager.py +285 -3
- htmlgraph/session_registry.py +587 -0
- htmlgraph/session_state.py +436 -0
- htmlgraph/session_warning.py +2 -1
- htmlgraph/sessions/__init__.py +23 -0
- htmlgraph/sessions/handoff.py +756 -0
- htmlgraph/system_prompts.py +450 -0
- htmlgraph/templates/orchestration-view.html +350 -0
- htmlgraph/track_builder.py +33 -1
- htmlgraph/track_manager.py +38 -0
- htmlgraph/transcript.py +18 -5
- htmlgraph/validation.py +115 -0
- htmlgraph/watch.py +2 -1
- htmlgraph/work_type_utils.py +2 -1
- {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/dashboard.html +2246 -248
- {htmlgraph-0.20.1.dist-info → htmlgraph-0.27.5.dist-info}/METADATA +95 -64
- htmlgraph-0.27.5.dist-info/RECORD +337 -0
- {htmlgraph-0.20.1.dist-info → htmlgraph-0.27.5.dist-info}/entry_points.txt +1 -1
- htmlgraph/cli.py +0 -4839
- htmlgraph/sdk.py +0 -2359
- htmlgraph-0.20.1.dist-info/RECORD +0 -118
- {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/styles.css +0 -0
- {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/AGENTS.md.template +0 -0
- {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/CLAUDE.md.template +0 -0
- {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/GEMINI.md.template +0 -0
- {htmlgraph-0.20.1.dist-info → htmlgraph-0.27.5.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,676 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
"""HtmlGraph CLI - Orchestration commands (Archive, Orchestrator, Claude)."""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
10
|
+
|
|
11
|
+
from rich.console import Console
|
|
12
|
+
|
|
13
|
+
from htmlgraph.cli.base import BaseCommand, CommandError, CommandResult
|
|
14
|
+
from htmlgraph.cli.constants import DEFAULT_GRAPH_DIR
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from argparse import _SubParsersAction
|
|
18
|
+
|
|
19
|
+
console = Console()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def register_archive_commands(subparsers: _SubParsersAction) -> None:
|
|
23
|
+
"""Register archive management commands."""
|
|
24
|
+
archive_parser = subparsers.add_parser("archive", help="Archive management")
|
|
25
|
+
archive_subparsers = archive_parser.add_subparsers(
|
|
26
|
+
dest="archive_command", help="Archive command"
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
# archive create
|
|
30
|
+
archive_create = archive_subparsers.add_parser("create", help="Create archive")
|
|
31
|
+
archive_create.add_argument("entity_id", help="Entity ID to archive")
|
|
32
|
+
archive_create.add_argument(
|
|
33
|
+
"--graph-dir", "-g", default=DEFAULT_GRAPH_DIR, help="Graph directory"
|
|
34
|
+
)
|
|
35
|
+
archive_create.add_argument(
|
|
36
|
+
"--format", choices=["json", "text"], default="text", help="Output format"
|
|
37
|
+
)
|
|
38
|
+
archive_create.set_defaults(func=ArchiveCreateCommand.from_args)
|
|
39
|
+
|
|
40
|
+
# archive list
|
|
41
|
+
archive_list = archive_subparsers.add_parser("list", help="List archives")
|
|
42
|
+
archive_list.add_argument(
|
|
43
|
+
"--graph-dir", "-g", default=DEFAULT_GRAPH_DIR, help="Graph directory"
|
|
44
|
+
)
|
|
45
|
+
archive_list.add_argument(
|
|
46
|
+
"--format", choices=["json", "text"], default="text", help="Output format"
|
|
47
|
+
)
|
|
48
|
+
archive_list.set_defaults(func=ArchiveListCommand.from_args)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def register_orchestrator_commands(subparsers: _SubParsersAction) -> None:
|
|
52
|
+
"""Register orchestrator commands."""
|
|
53
|
+
orchestrator_parser = subparsers.add_parser(
|
|
54
|
+
"orchestrator", help="Orchestrator management"
|
|
55
|
+
)
|
|
56
|
+
orchestrator_subparsers = orchestrator_parser.add_subparsers(
|
|
57
|
+
dest="orchestrator_command", help="Orchestrator command"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# orchestrator enable
|
|
61
|
+
orch_enable = orchestrator_subparsers.add_parser(
|
|
62
|
+
"enable", help="Enable orchestrator mode"
|
|
63
|
+
)
|
|
64
|
+
orch_enable.add_argument(
|
|
65
|
+
"--level",
|
|
66
|
+
"-l",
|
|
67
|
+
choices=["strict", "guidance"],
|
|
68
|
+
default="strict",
|
|
69
|
+
help="Enforcement level (default: strict)",
|
|
70
|
+
)
|
|
71
|
+
orch_enable.add_argument(
|
|
72
|
+
"--graph-dir", "-g", default=DEFAULT_GRAPH_DIR, help="Graph directory"
|
|
73
|
+
)
|
|
74
|
+
orch_enable.set_defaults(func=OrchestratorEnableCommand.from_args)
|
|
75
|
+
|
|
76
|
+
# orchestrator disable
|
|
77
|
+
orch_disable = orchestrator_subparsers.add_parser(
|
|
78
|
+
"disable", help="Disable orchestrator mode"
|
|
79
|
+
)
|
|
80
|
+
orch_disable.add_argument(
|
|
81
|
+
"--graph-dir", "-g", default=DEFAULT_GRAPH_DIR, help="Graph directory"
|
|
82
|
+
)
|
|
83
|
+
orch_disable.set_defaults(func=OrchestratorDisableCommand.from_args)
|
|
84
|
+
|
|
85
|
+
# orchestrator status
|
|
86
|
+
orch_status = orchestrator_subparsers.add_parser(
|
|
87
|
+
"status", help="Show orchestrator status"
|
|
88
|
+
)
|
|
89
|
+
orch_status.add_argument(
|
|
90
|
+
"--graph-dir", "-g", default=DEFAULT_GRAPH_DIR, help="Graph directory"
|
|
91
|
+
)
|
|
92
|
+
orch_status.add_argument(
|
|
93
|
+
"--format", choices=["json", "text"], default="text", help="Output format"
|
|
94
|
+
)
|
|
95
|
+
orch_status.set_defaults(func=OrchestratorStatusCommand.from_args)
|
|
96
|
+
|
|
97
|
+
# orchestrator config show
|
|
98
|
+
config_show = orchestrator_subparsers.add_parser(
|
|
99
|
+
"config-show", help="Show orchestrator configuration"
|
|
100
|
+
)
|
|
101
|
+
config_show.add_argument(
|
|
102
|
+
"--format", choices=["json", "text"], default="text", help="Output format"
|
|
103
|
+
)
|
|
104
|
+
config_show.set_defaults(func=OrchestratorConfigShowCommand.from_args)
|
|
105
|
+
|
|
106
|
+
# orchestrator config set
|
|
107
|
+
config_set = orchestrator_subparsers.add_parser(
|
|
108
|
+
"config-set", help="Set a configuration value"
|
|
109
|
+
)
|
|
110
|
+
config_set.add_argument(
|
|
111
|
+
"key", help="Config key (e.g., thresholds.exploration_calls)"
|
|
112
|
+
)
|
|
113
|
+
config_set.add_argument("value", type=int, help="New value")
|
|
114
|
+
config_set.add_argument(
|
|
115
|
+
"--format", choices=["json", "text"], default="text", help="Output format"
|
|
116
|
+
)
|
|
117
|
+
config_set.set_defaults(func=OrchestratorConfigSetCommand.from_args)
|
|
118
|
+
|
|
119
|
+
# orchestrator config reset
|
|
120
|
+
config_reset = orchestrator_subparsers.add_parser(
|
|
121
|
+
"config-reset", help="Reset configuration to defaults"
|
|
122
|
+
)
|
|
123
|
+
config_reset.add_argument(
|
|
124
|
+
"--format", choices=["json", "text"], default="text", help="Output format"
|
|
125
|
+
)
|
|
126
|
+
config_reset.set_defaults(func=OrchestratorConfigResetCommand.from_args)
|
|
127
|
+
|
|
128
|
+
# orchestrator reset-violations
|
|
129
|
+
reset_violations = orchestrator_subparsers.add_parser(
|
|
130
|
+
"reset-violations", help="Reset violation counter"
|
|
131
|
+
)
|
|
132
|
+
reset_violations.add_argument(
|
|
133
|
+
"--graph-dir", "-g", default=DEFAULT_GRAPH_DIR, help="Graph directory"
|
|
134
|
+
)
|
|
135
|
+
reset_violations.set_defaults(func=OrchestratorResetViolationsCommand.from_args)
|
|
136
|
+
|
|
137
|
+
# orchestrator set-level
|
|
138
|
+
set_level = orchestrator_subparsers.add_parser(
|
|
139
|
+
"set-level", help="Set enforcement level"
|
|
140
|
+
)
|
|
141
|
+
set_level.add_argument(
|
|
142
|
+
"level", choices=["strict", "guidance"], help="Enforcement level to set"
|
|
143
|
+
)
|
|
144
|
+
set_level.add_argument(
|
|
145
|
+
"--graph-dir", "-g", default=DEFAULT_GRAPH_DIR, help="Graph directory"
|
|
146
|
+
)
|
|
147
|
+
set_level.set_defaults(func=OrchestratorSetLevelCommand.from_args)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def register_claude_commands(subparsers: _SubParsersAction) -> None:
|
|
151
|
+
"""Register Claude Code launcher commands."""
|
|
152
|
+
claude_parser = subparsers.add_parser(
|
|
153
|
+
"claude", help="Launch Claude Code with HtmlGraph integration"
|
|
154
|
+
)
|
|
155
|
+
claude_parser.add_argument(
|
|
156
|
+
"--init",
|
|
157
|
+
action="store_true",
|
|
158
|
+
help="Launch with orchestrator prompt and plugin installation",
|
|
159
|
+
)
|
|
160
|
+
claude_parser.add_argument(
|
|
161
|
+
"--continue",
|
|
162
|
+
dest="continue_session",
|
|
163
|
+
action="store_true",
|
|
164
|
+
help="Resume last session with orchestrator rules",
|
|
165
|
+
)
|
|
166
|
+
claude_parser.add_argument(
|
|
167
|
+
"--dev",
|
|
168
|
+
action="store_true",
|
|
169
|
+
help="Launch with local plugin for development",
|
|
170
|
+
)
|
|
171
|
+
claude_parser.set_defaults(func=ClaudeCommand.from_args)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
# ============================================================================
|
|
175
|
+
# Archive Commands
|
|
176
|
+
# ============================================================================
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class ArchiveCreateCommand(BaseCommand):
|
|
180
|
+
"""Create an archive."""
|
|
181
|
+
|
|
182
|
+
def __init__(self, *, entity_id: str) -> None:
|
|
183
|
+
super().__init__()
|
|
184
|
+
self.entity_id = entity_id
|
|
185
|
+
|
|
186
|
+
@classmethod
|
|
187
|
+
def from_args(cls, args: argparse.Namespace) -> ArchiveCreateCommand:
|
|
188
|
+
return cls(entity_id=args.entity_id)
|
|
189
|
+
|
|
190
|
+
def execute(self) -> CommandResult:
|
|
191
|
+
"""Create an archive."""
|
|
192
|
+
from htmlgraph.archive import ArchiveManager
|
|
193
|
+
|
|
194
|
+
if self.graph_dir is None:
|
|
195
|
+
raise CommandError("Missing graph directory")
|
|
196
|
+
|
|
197
|
+
htmlgraph_dir = Path(self.graph_dir).resolve()
|
|
198
|
+
|
|
199
|
+
if not htmlgraph_dir.exists():
|
|
200
|
+
raise CommandError(f"Directory not found: {htmlgraph_dir}")
|
|
201
|
+
|
|
202
|
+
with console.status("[blue]Initializing archive manager...", spinner="dots"):
|
|
203
|
+
manager = ArchiveManager(htmlgraph_dir)
|
|
204
|
+
|
|
205
|
+
try:
|
|
206
|
+
# Archive the entity
|
|
207
|
+
with console.status(f"[blue]Archiving {self.entity_id}...", spinner="dots"):
|
|
208
|
+
# For now, we'll use the older_than_days parameter with 0 to archive immediately
|
|
209
|
+
result = manager.archive_entities(older_than_days=0, dry_run=False)
|
|
210
|
+
|
|
211
|
+
from htmlgraph.cli.base import TextOutputBuilder
|
|
212
|
+
|
|
213
|
+
output = TextOutputBuilder()
|
|
214
|
+
output.add_success(f"Archived: {self.entity_id}")
|
|
215
|
+
output.add_field(
|
|
216
|
+
"Created", f"{len(result['archive_files'])} archive file(s)"
|
|
217
|
+
)
|
|
218
|
+
output.add_field("Total entities archived", result["archived_count"])
|
|
219
|
+
|
|
220
|
+
json_data = {
|
|
221
|
+
"entity_id": self.entity_id,
|
|
222
|
+
"archived": True,
|
|
223
|
+
"archive_files": result["archive_files"],
|
|
224
|
+
"count": result["archived_count"],
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return CommandResult(
|
|
228
|
+
text=output.build(),
|
|
229
|
+
json_data=json_data,
|
|
230
|
+
)
|
|
231
|
+
finally:
|
|
232
|
+
manager.close()
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class ArchiveListCommand(BaseCommand):
|
|
236
|
+
"""List all archives."""
|
|
237
|
+
|
|
238
|
+
@classmethod
|
|
239
|
+
def from_args(cls, args: argparse.Namespace) -> ArchiveListCommand:
|
|
240
|
+
return cls()
|
|
241
|
+
|
|
242
|
+
def execute(self) -> CommandResult:
|
|
243
|
+
"""List all archives."""
|
|
244
|
+
if self.graph_dir is None:
|
|
245
|
+
raise CommandError("Missing graph directory")
|
|
246
|
+
|
|
247
|
+
htmlgraph_dir = Path(self.graph_dir).resolve()
|
|
248
|
+
|
|
249
|
+
if not htmlgraph_dir.exists():
|
|
250
|
+
raise CommandError(f"Directory not found: {htmlgraph_dir}")
|
|
251
|
+
|
|
252
|
+
archive_dir = htmlgraph_dir / "archives"
|
|
253
|
+
|
|
254
|
+
if not archive_dir.exists():
|
|
255
|
+
from htmlgraph.cli.base import TextOutputBuilder
|
|
256
|
+
|
|
257
|
+
output = TextOutputBuilder()
|
|
258
|
+
output.add_warning("No archives found.")
|
|
259
|
+
return CommandResult(
|
|
260
|
+
text=output.build(),
|
|
261
|
+
json_data={"archives": []},
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
archive_files = sorted(archive_dir.glob("*.html"))
|
|
265
|
+
|
|
266
|
+
if not archive_files:
|
|
267
|
+
from htmlgraph.cli.base import TextOutputBuilder
|
|
268
|
+
|
|
269
|
+
output = TextOutputBuilder()
|
|
270
|
+
output.add_warning("No archives found.")
|
|
271
|
+
return CommandResult(
|
|
272
|
+
text=output.build(),
|
|
273
|
+
json_data={"archives": []},
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
# Create Rich table
|
|
277
|
+
from htmlgraph.cli.base import TableBuilder
|
|
278
|
+
|
|
279
|
+
builder = TableBuilder.create_list_table(
|
|
280
|
+
f"Archive Files ({len(archive_files)})"
|
|
281
|
+
)
|
|
282
|
+
builder.add_column("Filename", style="cyan", no_wrap=False)
|
|
283
|
+
builder.add_numeric_column("Size (KB)", style="yellow", width=12)
|
|
284
|
+
builder.add_timestamp_column("Modified", width=16)
|
|
285
|
+
|
|
286
|
+
file_list = []
|
|
287
|
+
for f in archive_files:
|
|
288
|
+
size_kb = f.stat().st_size / 1024
|
|
289
|
+
modified = datetime.fromtimestamp(f.stat().st_mtime)
|
|
290
|
+
modified_str = modified.strftime("%Y-%m-%d %H:%M")
|
|
291
|
+
|
|
292
|
+
builder.add_row(f.name, f"{size_kb:.1f}", modified_str)
|
|
293
|
+
|
|
294
|
+
file_list.append(
|
|
295
|
+
{
|
|
296
|
+
"filename": f.name,
|
|
297
|
+
"size_kb": size_kb,
|
|
298
|
+
"modified": modified.isoformat(),
|
|
299
|
+
}
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
# Return table object directly - TextFormatter will print it properly
|
|
303
|
+
return CommandResult(
|
|
304
|
+
data=builder.table,
|
|
305
|
+
json_data={"archives": file_list},
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
# ============================================================================
|
|
310
|
+
# Orchestrator Commands
|
|
311
|
+
# ============================================================================
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
class OrchestratorEnableCommand(BaseCommand):
|
|
315
|
+
"""Enable orchestrator mode."""
|
|
316
|
+
|
|
317
|
+
def __init__(self, *, level: str = "strict") -> None:
|
|
318
|
+
super().__init__()
|
|
319
|
+
self.level: str = level
|
|
320
|
+
|
|
321
|
+
@classmethod
|
|
322
|
+
def from_args(cls, args: argparse.Namespace) -> OrchestratorEnableCommand:
|
|
323
|
+
return cls(level=getattr(args, "level", "strict"))
|
|
324
|
+
|
|
325
|
+
def execute(self) -> CommandResult:
|
|
326
|
+
"""Enable orchestrator mode."""
|
|
327
|
+
|
|
328
|
+
from htmlgraph.orchestrator_mode import OrchestratorModeManager
|
|
329
|
+
|
|
330
|
+
if self.graph_dir is None:
|
|
331
|
+
raise CommandError("Missing graph directory")
|
|
332
|
+
|
|
333
|
+
manager = OrchestratorModeManager(self.graph_dir)
|
|
334
|
+
manager.enable(level=self.level) # type: ignore[arg-type]
|
|
335
|
+
status = manager.status()
|
|
336
|
+
|
|
337
|
+
from htmlgraph.cli.base import TextOutputBuilder
|
|
338
|
+
|
|
339
|
+
output = TextOutputBuilder()
|
|
340
|
+
if self.level == "strict":
|
|
341
|
+
output.add_success("Orchestrator mode enabled (strict enforcement)")
|
|
342
|
+
else:
|
|
343
|
+
output.add_success("Orchestrator mode enabled (guidance mode)")
|
|
344
|
+
output.add_field("Level", self.level)
|
|
345
|
+
if status.get("activated_at"):
|
|
346
|
+
output.add_field("Activated at", status["activated_at"])
|
|
347
|
+
|
|
348
|
+
return CommandResult(
|
|
349
|
+
text=output.build(),
|
|
350
|
+
json_data=status,
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
class OrchestratorDisableCommand(BaseCommand):
|
|
355
|
+
"""Disable orchestrator mode."""
|
|
356
|
+
|
|
357
|
+
@classmethod
|
|
358
|
+
def from_args(cls, args: argparse.Namespace) -> OrchestratorDisableCommand:
|
|
359
|
+
return cls()
|
|
360
|
+
|
|
361
|
+
def execute(self) -> CommandResult:
|
|
362
|
+
"""Disable orchestrator mode."""
|
|
363
|
+
from htmlgraph.orchestrator_mode import OrchestratorModeManager
|
|
364
|
+
|
|
365
|
+
if self.graph_dir is None:
|
|
366
|
+
raise CommandError("Missing graph directory")
|
|
367
|
+
|
|
368
|
+
manager = OrchestratorModeManager(self.graph_dir)
|
|
369
|
+
manager.disable(by_user=True)
|
|
370
|
+
status = manager.status()
|
|
371
|
+
|
|
372
|
+
from htmlgraph.cli.base import TextOutputBuilder
|
|
373
|
+
|
|
374
|
+
output = TextOutputBuilder()
|
|
375
|
+
output.add_success("Orchestrator mode disabled")
|
|
376
|
+
output.add_field("Status", "Disabled by user (auto-activation prevented)")
|
|
377
|
+
|
|
378
|
+
return CommandResult(
|
|
379
|
+
text=output.build(),
|
|
380
|
+
json_data=status,
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
class OrchestratorStatusCommand(BaseCommand):
|
|
385
|
+
"""Show orchestrator status."""
|
|
386
|
+
|
|
387
|
+
@classmethod
|
|
388
|
+
def from_args(cls, args: argparse.Namespace) -> OrchestratorStatusCommand:
|
|
389
|
+
return cls()
|
|
390
|
+
|
|
391
|
+
def execute(self) -> CommandResult:
|
|
392
|
+
"""Show orchestrator status."""
|
|
393
|
+
from htmlgraph.orchestrator_mode import OrchestratorModeManager
|
|
394
|
+
|
|
395
|
+
if self.graph_dir is None:
|
|
396
|
+
raise CommandError("Missing graph directory")
|
|
397
|
+
|
|
398
|
+
manager = OrchestratorModeManager(self.graph_dir)
|
|
399
|
+
mode = manager.load()
|
|
400
|
+
status = manager.status()
|
|
401
|
+
|
|
402
|
+
from htmlgraph.cli.base import TextOutputBuilder
|
|
403
|
+
|
|
404
|
+
output = TextOutputBuilder()
|
|
405
|
+
if status.get("enabled"):
|
|
406
|
+
if status.get("enforcement_level") == "strict":
|
|
407
|
+
output.add_line("Orchestrator mode: enabled (strict enforcement)")
|
|
408
|
+
else:
|
|
409
|
+
output.add_line("Orchestrator mode: enabled (guidance mode)")
|
|
410
|
+
else:
|
|
411
|
+
output.add_line("Orchestrator mode: disabled")
|
|
412
|
+
if mode.disabled_by_user:
|
|
413
|
+
output.add_field(
|
|
414
|
+
"Status", "Disabled by user (auto-activation prevented)"
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
if status.get("activated_at"):
|
|
418
|
+
output.add_field("Activated at", status["activated_at"])
|
|
419
|
+
if status.get("violations") is not None:
|
|
420
|
+
output.add_field("Violations", f"{status['violations']}/3")
|
|
421
|
+
if status.get("circuit_breaker_triggered"):
|
|
422
|
+
output.add_field("Circuit breaker", "TRIGGERED")
|
|
423
|
+
|
|
424
|
+
return CommandResult(
|
|
425
|
+
data=status,
|
|
426
|
+
text=output.build(),
|
|
427
|
+
json_data=status,
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
class OrchestratorConfigShowCommand(BaseCommand):
|
|
432
|
+
"""Show orchestrator configuration."""
|
|
433
|
+
|
|
434
|
+
@classmethod
|
|
435
|
+
def from_args(cls, args: argparse.Namespace) -> OrchestratorConfigShowCommand:
|
|
436
|
+
return cls()
|
|
437
|
+
|
|
438
|
+
def execute(self) -> CommandResult:
|
|
439
|
+
"""Show orchestrator configuration."""
|
|
440
|
+
from htmlgraph.orchestrator_config import (
|
|
441
|
+
format_config_display,
|
|
442
|
+
load_orchestrator_config,
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
config = load_orchestrator_config()
|
|
446
|
+
text_output = format_config_display(config)
|
|
447
|
+
|
|
448
|
+
return CommandResult(
|
|
449
|
+
text=text_output,
|
|
450
|
+
json_data=config.model_dump(),
|
|
451
|
+
)
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
class OrchestratorConfigSetCommand(BaseCommand):
|
|
455
|
+
"""Set a configuration value."""
|
|
456
|
+
|
|
457
|
+
def __init__(self, *, key: str, value: int) -> None:
|
|
458
|
+
super().__init__()
|
|
459
|
+
self.key = key
|
|
460
|
+
self.value = value
|
|
461
|
+
|
|
462
|
+
@classmethod
|
|
463
|
+
def from_args(cls, args: argparse.Namespace) -> OrchestratorConfigSetCommand:
|
|
464
|
+
return cls(key=args.key, value=args.value)
|
|
465
|
+
|
|
466
|
+
def execute(self) -> CommandResult:
|
|
467
|
+
"""Set a configuration value."""
|
|
468
|
+
from htmlgraph.orchestrator_config import (
|
|
469
|
+
get_config_paths,
|
|
470
|
+
load_orchestrator_config,
|
|
471
|
+
save_orchestrator_config,
|
|
472
|
+
set_config_value,
|
|
473
|
+
)
|
|
474
|
+
|
|
475
|
+
# Load current config
|
|
476
|
+
config = load_orchestrator_config()
|
|
477
|
+
|
|
478
|
+
try:
|
|
479
|
+
# Set the value
|
|
480
|
+
set_config_value(config, self.key, self.value)
|
|
481
|
+
|
|
482
|
+
# Save to first config path (project-specific)
|
|
483
|
+
config_path = get_config_paths()[0]
|
|
484
|
+
save_orchestrator_config(config, config_path)
|
|
485
|
+
|
|
486
|
+
from htmlgraph.cli.base import TextOutputBuilder
|
|
487
|
+
|
|
488
|
+
output = TextOutputBuilder()
|
|
489
|
+
output.add_success(f"Configuration updated: {self.key} = {self.value}")
|
|
490
|
+
output.add_field("Config file", str(config_path))
|
|
491
|
+
|
|
492
|
+
return CommandResult(
|
|
493
|
+
text=output.build(),
|
|
494
|
+
json_data={
|
|
495
|
+
"key": self.key,
|
|
496
|
+
"value": self.value,
|
|
497
|
+
"path": str(config_path),
|
|
498
|
+
},
|
|
499
|
+
)
|
|
500
|
+
except KeyError as e:
|
|
501
|
+
raise CommandError(f"Invalid config key: {e}")
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
class OrchestratorConfigResetCommand(BaseCommand):
|
|
505
|
+
"""Reset configuration to defaults."""
|
|
506
|
+
|
|
507
|
+
@classmethod
|
|
508
|
+
def from_args(cls, args: argparse.Namespace) -> OrchestratorConfigResetCommand:
|
|
509
|
+
return cls()
|
|
510
|
+
|
|
511
|
+
def execute(self) -> CommandResult:
|
|
512
|
+
"""Reset configuration to defaults."""
|
|
513
|
+
from htmlgraph.orchestrator_config import (
|
|
514
|
+
OrchestratorConfig,
|
|
515
|
+
get_config_paths,
|
|
516
|
+
save_orchestrator_config,
|
|
517
|
+
)
|
|
518
|
+
|
|
519
|
+
# Create default config
|
|
520
|
+
config = OrchestratorConfig()
|
|
521
|
+
|
|
522
|
+
# Save to first config path (project-specific)
|
|
523
|
+
config_path = get_config_paths()[0]
|
|
524
|
+
save_orchestrator_config(config, config_path)
|
|
525
|
+
|
|
526
|
+
from htmlgraph.cli.base import TextOutputBuilder
|
|
527
|
+
|
|
528
|
+
output = TextOutputBuilder()
|
|
529
|
+
output.add_success("Configuration reset to defaults")
|
|
530
|
+
output.add_field("Config file", str(config_path))
|
|
531
|
+
output.add_field("Exploration calls", config.thresholds.exploration_calls)
|
|
532
|
+
output.add_field(
|
|
533
|
+
"Circuit breaker", config.thresholds.circuit_breaker_violations
|
|
534
|
+
)
|
|
535
|
+
output.add_field(
|
|
536
|
+
"Violation decay", f"{config.thresholds.violation_decay_seconds}s"
|
|
537
|
+
)
|
|
538
|
+
|
|
539
|
+
return CommandResult(
|
|
540
|
+
text=output.build(),
|
|
541
|
+
json_data=config.model_dump(),
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
|
|
545
|
+
class OrchestratorResetViolationsCommand(BaseCommand):
|
|
546
|
+
"""Reset violation counter."""
|
|
547
|
+
|
|
548
|
+
@classmethod
|
|
549
|
+
def from_args(cls, args: argparse.Namespace) -> OrchestratorResetViolationsCommand:
|
|
550
|
+
return cls()
|
|
551
|
+
|
|
552
|
+
def execute(self) -> CommandResult:
|
|
553
|
+
"""Reset violation counter."""
|
|
554
|
+
from htmlgraph.orchestrator_mode import OrchestratorModeManager
|
|
555
|
+
|
|
556
|
+
if self.graph_dir is None:
|
|
557
|
+
raise CommandError("Missing graph directory")
|
|
558
|
+
|
|
559
|
+
manager = OrchestratorModeManager(self.graph_dir)
|
|
560
|
+
|
|
561
|
+
if not manager.status().get("enabled"):
|
|
562
|
+
console.print("[yellow]Orchestrator mode is not enabled[/yellow]")
|
|
563
|
+
return CommandResult(
|
|
564
|
+
text="Orchestrator mode is not enabled",
|
|
565
|
+
json_data={"success": False, "message": "not enabled"},
|
|
566
|
+
)
|
|
567
|
+
|
|
568
|
+
manager.reset_violations()
|
|
569
|
+
status = manager.status()
|
|
570
|
+
|
|
571
|
+
from htmlgraph.cli.base import TextOutputBuilder
|
|
572
|
+
|
|
573
|
+
output = TextOutputBuilder()
|
|
574
|
+
output.add_success("Violations reset")
|
|
575
|
+
output.add_field("Violation count", status.get("violations", 0))
|
|
576
|
+
output.add_field(
|
|
577
|
+
"Circuit breaker",
|
|
578
|
+
"Normal" if not status.get("circuit_breaker_triggered") else "TRIGGERED",
|
|
579
|
+
)
|
|
580
|
+
|
|
581
|
+
return CommandResult(
|
|
582
|
+
text=output.build(),
|
|
583
|
+
json_data=status,
|
|
584
|
+
)
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
class OrchestratorSetLevelCommand(BaseCommand):
|
|
588
|
+
"""Set enforcement level."""
|
|
589
|
+
|
|
590
|
+
def __init__(self, *, level: str) -> None:
|
|
591
|
+
super().__init__()
|
|
592
|
+
self.level: str = level
|
|
593
|
+
|
|
594
|
+
@classmethod
|
|
595
|
+
def from_args(cls, args: argparse.Namespace) -> OrchestratorSetLevelCommand:
|
|
596
|
+
return cls(level=args.level)
|
|
597
|
+
|
|
598
|
+
def execute(self) -> CommandResult:
|
|
599
|
+
"""Set enforcement level."""
|
|
600
|
+
from htmlgraph.orchestrator_mode import OrchestratorModeManager
|
|
601
|
+
|
|
602
|
+
if self.graph_dir is None:
|
|
603
|
+
raise CommandError("Missing graph directory")
|
|
604
|
+
|
|
605
|
+
manager = OrchestratorModeManager(self.graph_dir)
|
|
606
|
+
manager.set_level(self.level) # type: ignore[arg-type]
|
|
607
|
+
status = manager.status()
|
|
608
|
+
|
|
609
|
+
from htmlgraph.cli.base import TextOutputBuilder
|
|
610
|
+
|
|
611
|
+
output = TextOutputBuilder()
|
|
612
|
+
output.add_success(f"Enforcement level changed to '{self.level}'")
|
|
613
|
+
if self.level == "strict":
|
|
614
|
+
output.add_field("Mode", "Strict enforcement")
|
|
615
|
+
else:
|
|
616
|
+
output.add_field("Mode", "Guidance mode")
|
|
617
|
+
|
|
618
|
+
return CommandResult(
|
|
619
|
+
text=output.build(),
|
|
620
|
+
json_data=status,
|
|
621
|
+
)
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
# ============================================================================
|
|
625
|
+
# Claude Code Launcher Commands
|
|
626
|
+
# ============================================================================
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
class ClaudeCommand(BaseCommand):
|
|
630
|
+
"""Launch Claude Code with HtmlGraph integration."""
|
|
631
|
+
|
|
632
|
+
def __init__(
|
|
633
|
+
self,
|
|
634
|
+
*,
|
|
635
|
+
init: bool,
|
|
636
|
+
continue_session: bool,
|
|
637
|
+
dev: bool,
|
|
638
|
+
quiet: bool,
|
|
639
|
+
format: str,
|
|
640
|
+
) -> None:
|
|
641
|
+
super().__init__()
|
|
642
|
+
self.init = init
|
|
643
|
+
self.continue_session = continue_session
|
|
644
|
+
self.dev = dev
|
|
645
|
+
self.quiet = quiet
|
|
646
|
+
self.format = format
|
|
647
|
+
|
|
648
|
+
@classmethod
|
|
649
|
+
def from_args(cls, args: argparse.Namespace) -> ClaudeCommand:
|
|
650
|
+
return cls(
|
|
651
|
+
init=getattr(args, "init", False),
|
|
652
|
+
continue_session=getattr(args, "continue_session", False),
|
|
653
|
+
dev=getattr(args, "dev", False),
|
|
654
|
+
quiet=getattr(args, "quiet", False),
|
|
655
|
+
format=getattr(args, "format", "text"),
|
|
656
|
+
)
|
|
657
|
+
|
|
658
|
+
def execute(self) -> CommandResult:
|
|
659
|
+
"""Launch Claude Code."""
|
|
660
|
+
from htmlgraph.orchestration.claude_launcher import ClaudeLauncher
|
|
661
|
+
|
|
662
|
+
# Create args namespace for launcher
|
|
663
|
+
launcher_args = argparse.Namespace(
|
|
664
|
+
init=self.init,
|
|
665
|
+
continue_session=self.continue_session,
|
|
666
|
+
dev=self.dev,
|
|
667
|
+
quiet=self.quiet,
|
|
668
|
+
format=self.format,
|
|
669
|
+
)
|
|
670
|
+
|
|
671
|
+
# Launch Claude Code
|
|
672
|
+
launcher = ClaudeLauncher(launcher_args)
|
|
673
|
+
launcher.launch()
|
|
674
|
+
|
|
675
|
+
# This won't be reached because launcher.launch() calls subprocess
|
|
676
|
+
return CommandResult(text="Claude Code launched")
|