orchex 0.2.2__tar.gz → 0.2.3__tar.gz

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.
Files changed (148) hide show
  1. {orchex-0.2.2 → orchex-0.2.3}/.claude/skills/checkpointing/scripts/checkpoint.py +1 -1
  2. {orchex-0.2.2 → orchex-0.2.3}/.codex/skills/checkpointing/scripts/checkpoint.py +1 -1
  3. {orchex-0.2.2 → orchex-0.2.3}/.gitignore +1 -0
  4. {orchex-0.2.2 → orchex-0.2.3}/PKG-INFO +1 -1
  5. orchex-0.2.3/ai_orchestra/_version.py +24 -0
  6. {orchex-0.2.2 → orchex-0.2.3}/facets/scripts/checkpoint.py +1 -1
  7. {orchex-0.2.2 → orchex-0.2.3}/packages/codex-suggestions/tests/test_check_codex_after_plan.py +1 -1
  8. {orchex-0.2.2 → orchex-0.2.3}/packages/core/hooks/inject-shared-context.py +8 -5
  9. {orchex-0.2.2 → orchex-0.2.3}/packages/core/hooks/load-task-state.py +3 -3
  10. {orchex-0.2.2 → orchex-0.2.3}/packages/core/hooks/update-working-context.py +5 -0
  11. {orchex-0.2.2 → orchex-0.2.3}/packages/core/tests/test_hook_common.py +9 -3
  12. {orchex-0.2.2 → orchex-0.2.3}/scripts/lib/hook_utils.py +1 -1
  13. {orchex-0.2.2 → orchex-0.2.3}/scripts/lib/orchestra_context.py +22 -5
  14. {orchex-0.2.2 → orchex-0.2.3}/scripts/lib/orchestra_hooks.py +5 -4
  15. orchex-0.2.2/ai_orchestra/_version.py +0 -34
  16. {orchex-0.2.2 → orchex-0.2.3}/CLAUDE.md +0 -0
  17. {orchex-0.2.2 → orchex-0.2.3}/README.md +0 -0
  18. {orchex-0.2.2 → orchex-0.2.3}/ai_orchestra/__init__.py +0 -0
  19. {orchex-0.2.2 → orchex-0.2.3}/ai_orchestra/cli.py +0 -0
  20. {orchex-0.2.2 → orchex-0.2.3}/packages/README.md +0 -0
  21. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/ai-architect.md +0 -0
  22. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/ai-dev.md +0 -0
  23. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/api-designer.md +0 -0
  24. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/architect.md +0 -0
  25. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/architecture-reviewer.md +0 -0
  26. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/auth-designer.md +0 -0
  27. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/backend-go-dev.md +0 -0
  28. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/backend-python-dev.md +0 -0
  29. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/code-reviewer.md +0 -0
  30. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/data-modeler.md +0 -0
  31. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/debugger.md +0 -0
  32. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/docs-writer.md +0 -0
  33. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/frontend-dev.md +0 -0
  34. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/general-purpose.md +0 -0
  35. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/performance-reviewer.md +0 -0
  36. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/planner.md +0 -0
  37. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/prompt-engineer.md +0 -0
  38. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/rag-engineer.md +0 -0
  39. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/requirements.md +0 -0
  40. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/researcher.md +0 -0
  41. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/security-reviewer.md +0 -0
  42. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/spec-reviewer.md +0 -0
  43. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/spec-writer.md +0 -0
  44. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/specialized-mcp-builder.md +0 -0
  45. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/support-executive-summary-generator.md +0 -0
  46. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/tester.md +0 -0
  47. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/testing-reality-checker.md +0 -0
  48. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/agents/ux-reviewer.md +0 -0
  49. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/config/cli-tools.yaml +0 -0
  50. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/hooks/agent-router.py +0 -0
  51. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/hooks/route_config.py +0 -0
  52. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/manifest.json +0 -0
  53. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/tests/test_agent_router.py +0 -0
  54. {orchex-0.2.2 → orchex-0.2.3}/packages/agent-routing/tests/test_agent_router_e2e.py +0 -0
  55. {orchex-0.2.2 → orchex-0.2.3}/packages/cli-logging/hooks/log-cli-tools.py +0 -0
  56. {orchex-0.2.2 → orchex-0.2.3}/packages/cli-logging/manifest.json +0 -0
  57. {orchex-0.2.2 → orchex-0.2.3}/packages/cli-logging/scripts/analyze-cli-usage.py +0 -0
  58. {orchex-0.2.2 → orchex-0.2.3}/packages/cli-logging/tests/test_analyze_cli_usage.py +0 -0
  59. {orchex-0.2.2 → orchex-0.2.3}/packages/cli-logging/tests/test_log_cli_tools.py +0 -0
  60. {orchex-0.2.2 → orchex-0.2.3}/packages/cocoindex/config/cocoindex.yaml +0 -0
  61. {orchex-0.2.2 → orchex-0.2.3}/packages/cocoindex/hooks/provision-mcp-servers.py +0 -0
  62. {orchex-0.2.2 → orchex-0.2.3}/packages/cocoindex/hooks/proxy_manager.py +0 -0
  63. {orchex-0.2.2 → orchex-0.2.3}/packages/cocoindex/hooks/stop-mcp-proxy.py +0 -0
  64. {orchex-0.2.2 → orchex-0.2.3}/packages/cocoindex/manifest.json +0 -0
  65. {orchex-0.2.2 → orchex-0.2.3}/packages/cocoindex/tests/test_provision.py +0 -0
  66. {orchex-0.2.2 → orchex-0.2.3}/packages/cocoindex/tests/test_proxy_manager.py +0 -0
  67. {orchex-0.2.2 → orchex-0.2.3}/packages/codex-suggestions/hooks/check-codex-after-plan.py +0 -0
  68. {orchex-0.2.2 → orchex-0.2.3}/packages/codex-suggestions/hooks/check-codex-before-write.py +0 -0
  69. {orchex-0.2.2 → orchex-0.2.3}/packages/codex-suggestions/manifest.json +0 -0
  70. {orchex-0.2.2 → orchex-0.2.3}/packages/codex-suggestions/tests/test_check_codex_before_write.py +0 -0
  71. {orchex-0.2.2 → orchex-0.2.3}/packages/core/config/task-memory.yaml +0 -0
  72. {orchex-0.2.2 → orchex-0.2.3}/packages/core/hooks/capture-task-result.py +0 -0
  73. {orchex-0.2.2 → orchex-0.2.3}/packages/core/hooks/check-plan-gate.py +0 -0
  74. {orchex-0.2.2 → orchex-0.2.3}/packages/core/hooks/cleanup-session-context.py +0 -0
  75. {orchex-0.2.2 → orchex-0.2.3}/packages/core/hooks/clear-plan-gate.py +0 -0
  76. {orchex-0.2.2 → orchex-0.2.3}/packages/core/hooks/context_store.py +0 -0
  77. {orchex-0.2.2 → orchex-0.2.3}/packages/core/hooks/hook_common.py +0 -0
  78. {orchex-0.2.2 → orchex-0.2.3}/packages/core/hooks/log_common.py +0 -0
  79. {orchex-0.2.2 → orchex-0.2.3}/packages/core/hooks/set-plan-gate.py +0 -0
  80. {orchex-0.2.2 → orchex-0.2.3}/packages/core/manifest.json +0 -0
  81. {orchex-0.2.2 → orchex-0.2.3}/packages/core/tests/test_config_loading.py +0 -0
  82. {orchex-0.2.2 → orchex-0.2.3}/packages/core/tests/test_load_task_state.py +0 -0
  83. {orchex-0.2.2 → orchex-0.2.3}/packages/core/tests/test_log_common.py +0 -0
  84. {orchex-0.2.2 → orchex-0.2.3}/packages/core/tests/test_plan_gate.py +0 -0
  85. {orchex-0.2.2 → orchex-0.2.3}/packages/gemini-suggestions/hooks/suggest-gemini-research.py +0 -0
  86. {orchex-0.2.2 → orchex-0.2.3}/packages/gemini-suggestions/manifest.json +0 -0
  87. {orchex-0.2.2 → orchex-0.2.3}/packages/gemini-suggestions/tests/test_suggest_gemini_research.py +0 -0
  88. {orchex-0.2.2 → orchex-0.2.3}/packages/issue-workflow/config/sandbox-requirements.json +0 -0
  89. {orchex-0.2.2 → orchex-0.2.3}/packages/issue-workflow/manifest.json +0 -0
  90. {orchex-0.2.2 → orchex-0.2.3}/packages/quality-gates/hooks/lint-on-save.py +0 -0
  91. {orchex-0.2.2 → orchex-0.2.3}/packages/quality-gates/hooks/post-implementation-review.py +0 -0
  92. {orchex-0.2.2 → orchex-0.2.3}/packages/quality-gates/hooks/post-test-analysis.py +0 -0
  93. {orchex-0.2.2 → orchex-0.2.3}/packages/quality-gates/hooks/test-gate-checker.py +0 -0
  94. {orchex-0.2.2 → orchex-0.2.3}/packages/quality-gates/manifest.json +0 -0
  95. {orchex-0.2.2 → orchex-0.2.3}/packages/quality-gates/tests/test_post_test_analysis.py +0 -0
  96. {orchex-0.2.2 → orchex-0.2.3}/packages/quality-gates/tests/test_test_gate_checker.py +0 -0
  97. {orchex-0.2.2 → orchex-0.2.3}/packages/route-audit/config/delegation-policy.json +0 -0
  98. {orchex-0.2.2 → orchex-0.2.3}/packages/route-audit/config/orchestration-flags.json +0 -0
  99. {orchex-0.2.2 → orchex-0.2.3}/packages/route-audit/hooks/orchestration-bootstrap.py +0 -0
  100. {orchex-0.2.2 → orchex-0.2.3}/packages/route-audit/hooks/orchestration-expected-route.py +0 -0
  101. {orchex-0.2.2 → orchex-0.2.3}/packages/route-audit/hooks/orchestration-route-audit.py +0 -0
  102. {orchex-0.2.2 → orchex-0.2.3}/packages/route-audit/manifest.json +0 -0
  103. {orchex-0.2.2 → orchex-0.2.3}/packages/route-audit/scripts/dashboard.py +0 -0
  104. {orchex-0.2.2 → orchex-0.2.3}/packages/route-audit/scripts/log-viewer.py +0 -0
  105. {orchex-0.2.2 → orchex-0.2.3}/packages/route-audit/scripts/orchestration-kpi-report.py +0 -0
  106. {orchex-0.2.2 → orchex-0.2.3}/packages/route-audit/tests/test_route_audit.py +0 -0
  107. {orchex-0.2.2 → orchex-0.2.3}/packages/route-audit/tests/test_route_audit_orchestration_hooks.py +0 -0
  108. {orchex-0.2.2 → orchex-0.2.3}/packages/tmux-monitor/hooks/tmux-format-output.py +0 -0
  109. {orchex-0.2.2 → orchex-0.2.3}/packages/tmux-monitor/hooks/tmux-pre-task.py +0 -0
  110. {orchex-0.2.2 → orchex-0.2.3}/packages/tmux-monitor/hooks/tmux-session-end.py +0 -0
  111. {orchex-0.2.2 → orchex-0.2.3}/packages/tmux-monitor/hooks/tmux-session-start.py +0 -0
  112. {orchex-0.2.2 → orchex-0.2.3}/packages/tmux-monitor/hooks/tmux-subagent-start.py +0 -0
  113. {orchex-0.2.2 → orchex-0.2.3}/packages/tmux-monitor/hooks/tmux-subagent-stop.py +0 -0
  114. {orchex-0.2.2 → orchex-0.2.3}/packages/tmux-monitor/hooks/tmux_common.py +0 -0
  115. {orchex-0.2.2 → orchex-0.2.3}/packages/tmux-monitor/manifest.json +0 -0
  116. {orchex-0.2.2 → orchex-0.2.3}/packages/tmux-monitor/tests/test_tmux_monitor_hooks.py +0 -0
  117. {orchex-0.2.2 → orchex-0.2.3}/presets.json +0 -0
  118. {orchex-0.2.2 → orchex-0.2.3}/pyproject.toml +0 -0
  119. {orchex-0.2.2 → orchex-0.2.3}/scripts/lib/__init__.py +0 -0
  120. {orchex-0.2.2 → orchex-0.2.3}/scripts/lib/agent_model_patch.py +0 -0
  121. {orchex-0.2.2 → orchex-0.2.3}/scripts/lib/facet_builder.py +0 -0
  122. {orchex-0.2.2 → orchex-0.2.3}/scripts/lib/gitignore_sync.py +0 -0
  123. {orchex-0.2.2 → orchex-0.2.3}/scripts/lib/orchestra_models.py +0 -0
  124. {orchex-0.2.2 → orchex-0.2.3}/scripts/lib/scaffold.py +0 -0
  125. {orchex-0.2.2 → orchex-0.2.3}/scripts/lib/settings_io.py +0 -0
  126. {orchex-0.2.2 → orchex-0.2.3}/scripts/lib/sync_engine.py +0 -0
  127. {orchex-0.2.2 → orchex-0.2.3}/scripts/orchestra-manager.py +0 -0
  128. {orchex-0.2.2 → orchex-0.2.3}/scripts/sync-orchestra.py +0 -0
  129. {orchex-0.2.2 → orchex-0.2.3}/templates/codex/AGENTS.md +0 -0
  130. {orchex-0.2.2 → orchex-0.2.3}/templates/codex/config.toml +0 -0
  131. {orchex-0.2.2 → orchex-0.2.3}/templates/codex/skills/context-loader/SKILL.md +0 -0
  132. {orchex-0.2.2 → orchex-0.2.3}/templates/context/claude.md +0 -0
  133. {orchex-0.2.2 → orchex-0.2.3}/templates/context/codex.md +0 -0
  134. {orchex-0.2.2 → orchex-0.2.3}/templates/context/gemini.md +0 -0
  135. {orchex-0.2.2 → orchex-0.2.3}/templates/context/shared.md +0 -0
  136. {orchex-0.2.2 → orchex-0.2.3}/templates/gemini/GEMINI.md +0 -0
  137. {orchex-0.2.2 → orchex-0.2.3}/templates/gemini/settings.json +0 -0
  138. {orchex-0.2.2 → orchex-0.2.3}/templates/gemini/skills/context-loader/SKILL.md +0 -0
  139. {orchex-0.2.2 → orchex-0.2.3}/templates/project/.claudeignore +0 -0
  140. {orchex-0.2.2 → orchex-0.2.3}/templates/project/.claudeignore.local.example +0 -0
  141. {orchex-0.2.2 → orchex-0.2.3}/templates/project/CLAUDE.md +0 -0
  142. {orchex-0.2.2 → orchex-0.2.3}/templates/project/Plans.md +0 -0
  143. {orchex-0.2.2 → orchex-0.2.3}/templates/project/checkpoints/.gitkeep +0 -0
  144. {orchex-0.2.2 → orchex-0.2.3}/templates/project/docs/DESIGN.md +0 -0
  145. {orchex-0.2.2 → orchex-0.2.3}/templates/project/docs/libraries/_TEMPLATE.md +0 -0
  146. {orchex-0.2.2 → orchex-0.2.3}/templates/project/docs/research/.gitkeep +0 -0
  147. {orchex-0.2.2 → orchex-0.2.3}/templates/project/logs/orchestration/.gitkeep +0 -0
  148. {orchex-0.2.2 → orchex-0.2.3}/templates/project/state/.gitkeep +0 -0
@@ -205,7 +205,7 @@ def get_file_stats(since: str | None = None) -> dict[str, tuple[int, int]]:
205
205
  return stats
206
206
 
207
207
 
208
- def summarize_entries(entries: list[dict]) -> dict[str, list[dict]]:
208
+ def summarize_entries(entries: list[dict]) -> dict[str, dict[str, list[dict]]]:
209
209
  """Group and summarize entries by tool and date."""
210
210
  by_date: dict[str, dict[str, list]] = {}
211
211
 
@@ -205,7 +205,7 @@ def get_file_stats(since: str | None = None) -> dict[str, tuple[int, int]]:
205
205
  return stats
206
206
 
207
207
 
208
- def summarize_entries(entries: list[dict]) -> dict[str, list[dict]]:
208
+ def summarize_entries(entries: list[dict]) -> dict[str, dict[str, list[dict]]]:
209
209
  """Group and summarize entries by tool and date."""
210
210
  by_date: dict[str, dict[str, list]] = {}
211
211
 
@@ -30,6 +30,7 @@ env/
30
30
  *.log
31
31
 
32
32
  .claude/.mcp-proxy.pid
33
+ .worktrees/
33
34
 
34
35
  # CocoIndex local search index
35
36
  .cocoindex_code/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: orchex
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Multi-agent orchestration framework for Claude Code + Codex CLI + Gemini CLI
5
5
  License-Expression: MIT
6
6
  Requires-Python: >=3.12
@@ -0,0 +1,24 @@
1
+ # file generated by vcs-versioning
2
+ # don't change, don't track in version control
3
+ from __future__ import annotations
4
+
5
+ __all__ = [
6
+ "__version__",
7
+ "__version_tuple__",
8
+ "version",
9
+ "version_tuple",
10
+ "__commit_id__",
11
+ "commit_id",
12
+ ]
13
+
14
+ version: str
15
+ __version__: str
16
+ __version_tuple__: tuple[int | str, ...]
17
+ version_tuple: tuple[int | str, ...]
18
+ commit_id: str | None
19
+ __commit_id__: str | None
20
+
21
+ __version__ = version = '0.2.3'
22
+ __version_tuple__ = version_tuple = (0, 2, 3)
23
+
24
+ __commit_id__ = commit_id = None
@@ -205,7 +205,7 @@ def get_file_stats(since: str | None = None) -> dict[str, tuple[int, int]]:
205
205
  return stats
206
206
 
207
207
 
208
- def summarize_entries(entries: list[dict]) -> dict[str, list[dict]]:
208
+ def summarize_entries(entries: list[dict]) -> dict[str, dict[str, list[dict]]]:
209
209
  """Group and summarize entries by tool and date."""
210
210
  by_date: dict[str, dict[str, list]] = {}
211
211
 
@@ -62,7 +62,7 @@ def test_is_plan_agent_task_false_for_missing_fields() -> None:
62
62
  # --- main (stdout/exit-code integration) ---
63
63
 
64
64
 
65
- def _run_main_with_stdin(data: dict) -> tuple[str, int]:
65
+ def _run_main_with_stdin(data: dict) -> tuple[str, str | int]:
66
66
  """main() を stdin モックで実行し (stdout, exit_code) を返す。"""
67
67
  import io
68
68
  import sys
@@ -188,14 +188,17 @@ def main() -> None:
188
188
  if not injection:
189
189
  return
190
190
 
191
+ # additionalContext: オーケストレーターに表示される
192
+ # updatedInput: サブエージェントの prompt に直接注入される
191
193
  original_prompt = tool_input.get("prompt") or ""
192
- new_prompt = original_prompt + injection
193
-
194
- new_tool_input = {**tool_input, "prompt": new_prompt}
194
+ new_tool_input = {**tool_input, "prompt": original_prompt + injection}
195
195
 
196
196
  output = {
197
- "decision": "approve",
198
- "tool_input": new_tool_input,
197
+ "hookSpecificOutput": {
198
+ "hookEventName": "PreToolUse",
199
+ "additionalContext": injection.strip(),
200
+ "updatedInput": new_tool_input,
201
+ }
199
202
  }
200
203
  print(json.dumps(output, ensure_ascii=False))
201
204
 
@@ -130,7 +130,7 @@ def parse_tasks(
130
130
  content: str,
131
131
  marker_pattern: re.Pattern[str] | None = None,
132
132
  marker_to_state: dict[str, str] | None = None,
133
- ) -> dict[str, list[dict[str, str]]]:
133
+ ) -> dict[str, list[dict[str, str | None]]]:
134
134
  """Plans.md の内容からタスクを状態別に分類する。
135
135
 
136
136
  Returns:
@@ -142,7 +142,7 @@ def parse_tasks(
142
142
  if marker_to_state is None:
143
143
  marker_to_state = DEFAULT_MARKER_TO_STATE
144
144
 
145
- tasks: dict[str, list[dict[str, str]]] = {
145
+ tasks: dict[str, list[dict[str, str | None]]] = {
146
146
  "WIP": [],
147
147
  "TODO": [],
148
148
  "done": [],
@@ -182,7 +182,7 @@ def parse_tasks(
182
182
  return tasks
183
183
 
184
184
 
185
- def format_summary(tasks: dict[str, list[dict[str, str]]], max_display: int | None) -> str:
185
+ def format_summary(tasks: dict[str, list[dict[str, str | None]]], max_display: int | None) -> str:
186
186
  """タスク状態のサマリーをフォーマットする。"""
187
187
  parts: list[str] = []
188
188
 
@@ -54,6 +54,8 @@ try:
54
54
 
55
55
  _CONTEXT_STORE_AVAILABLE = True
56
56
  except ImportError:
57
+ from typing import Any
58
+
57
59
  _CONTEXT_STORE_AVAILABLE = False
58
60
 
59
61
  def get_project_dir(data: dict) -> str: # type: ignore[misc]
@@ -63,6 +65,9 @@ except ImportError:
63
65
  return cwd
64
66
  return os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd())
65
67
 
68
+ def update_working_context(project_dir: str, updates: dict[str, Any]) -> None:
69
+ """フォールバック: context_store が利用不可なら何もしない。"""
70
+
66
71
 
67
72
  def to_relative_path(file_path: str, project_dir: str) -> str:
68
73
  """file_path から project_dir プレフィックスを除去して相対パスに変換する。
@@ -3,6 +3,8 @@ import json
3
3
  import sys
4
4
  from pathlib import Path
5
5
 
6
+ import pytest
7
+
6
8
  from tests.module_loader import load_module
7
9
 
8
10
  hook_common = load_module("hook_common", "packages/core/hooks/hook_common.py")
@@ -39,7 +41,7 @@ def _write_json(path: Path, data: dict) -> None:
39
41
 
40
42
  class TestLoadPackageConfig:
41
43
  def test_project_local_overrides_orchestra_base(
42
- self, tmp_path: Path, monkeypatch: object
44
+ self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
43
45
  ) -> None:
44
46
  """base が orchestra dir にあっても project dir の .local が優先される。"""
45
47
  orchestra_dir = tmp_path / "orchestra"
@@ -59,7 +61,9 @@ class TestLoadPackageConfig:
59
61
  assert result["key"] == "local" # local override が効いている
60
62
  assert result["only_base"] is True # base のキーは保持
61
63
 
62
- def test_falls_back_to_base_dir_local(self, tmp_path: Path, monkeypatch: object) -> None:
64
+ def test_falls_back_to_base_dir_local(
65
+ self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
66
+ ) -> None:
63
67
  """project dir に .local がない場合は base と同じディレクトリの .local を使う。"""
64
68
  config_dir = tmp_path / "project" / ".claude" / "config" / "mypkg"
65
69
  _write_json(config_dir / "settings.json", {"key": "base"})
@@ -70,7 +74,9 @@ class TestLoadPackageConfig:
70
74
  )
71
75
  assert result["key"] == "local-same-dir"
72
76
 
73
- def test_no_local_returns_base_only(self, tmp_path: Path, monkeypatch: object) -> None:
77
+ def test_no_local_returns_base_only(
78
+ self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
79
+ ) -> None:
74
80
  """local ファイルが存在しない場合は base のみ返す。"""
75
81
  config_dir = tmp_path / "project" / ".claude" / "config" / "mypkg"
76
82
  _write_json(config_dir / "settings.json", {"key": "base", "nested": {"a": 1}})
@@ -48,7 +48,7 @@ def add_hook_to_settings(
48
48
 
49
49
  hook_obj = {"type": "command", "command": command, "timeout": timeout}
50
50
 
51
- target_entry = None
51
+ target_entry: dict[str, Any] | None = None
52
52
  for entry in settings_hooks[event]:
53
53
  if matcher:
54
54
  if entry.get("matcher") == matcher:
@@ -4,18 +4,35 @@ from __future__ import annotations
4
4
 
5
5
  import sys
6
6
  from pathlib import Path
7
+ from typing import TYPE_CHECKING, Protocol
8
+
9
+ if TYPE_CHECKING:
10
+ ContextSpecEntry = tuple[str, str, str, str]
11
+
12
+
13
+ class _ContextHost(Protocol):
14
+ """ContextMixin が利用側に要求するインターフェース。"""
15
+
16
+ orchestra_dir: Path
17
+ CONTEXT_SPECS: tuple[ContextSpecEntry, ...]
18
+ CONTEXT_SHARED_REL: str
19
+
20
+ def get_project_dir(self, project: str | None) -> Path: ...
7
21
 
8
22
 
9
23
  class ContextMixin:
10
24
  """OrchestraManager に context 管理機能を提供する Mixin。
11
25
 
12
- 利用側で以下の属性・メソッドが必要:
13
- - self.orchestra_dir: Path
14
- - self.CONTEXT_SPECS: tuple
15
- - self.CONTEXT_SHARED_REL: str
16
- - self.get_project_dir(project) -> Path
26
+ 利用側は _ContextHost Protocol を満たすこと。
17
27
  """
18
28
 
29
+ # Protocol で宣言した属性を型チェッカーに認識させる
30
+ orchestra_dir: Path
31
+ CONTEXT_SPECS: tuple[ContextSpecEntry, ...]
32
+ CONTEXT_SHARED_REL: str
33
+
34
+ def get_project_dir(self, project: str | None) -> Path: ...
35
+
19
36
  def _load_context_file(self, path: Path) -> str:
20
37
  """context テンプレートファイルを読み込む(存在しなければ終了)。"""
21
38
  if not path.exists():
@@ -27,12 +27,13 @@ from lib.settings_io import (
27
27
  class HooksMixin:
28
28
  """OrchestraManager にフック管理機能を提供する Mixin。
29
29
 
30
- 利用側で以下の属性・メソッドが必要:
31
- - self.orchestra_dir: Path
32
- - self.SYNC_HOOK_COMMAND: str
33
- - self.SYNC_HOOK_TIMEOUT: int
30
+ 利用側は以下の属性を定義すること。
34
31
  """
35
32
 
33
+ orchestra_dir: Path
34
+ SYNC_HOOK_COMMAND: str
35
+ SYNC_HOOK_TIMEOUT: int
36
+
36
37
  # --- settings / orchestra.json I/O(settings_io に委譲) ---
37
38
 
38
39
  @staticmethod
@@ -1,34 +0,0 @@
1
- # file generated by setuptools-scm
2
- # don't change, don't track in version control
3
-
4
- __all__ = [
5
- "__version__",
6
- "__version_tuple__",
7
- "version",
8
- "version_tuple",
9
- "__commit_id__",
10
- "commit_id",
11
- ]
12
-
13
- TYPE_CHECKING = False
14
- if TYPE_CHECKING:
15
- from typing import Tuple
16
- from typing import Union
17
-
18
- VERSION_TUPLE = Tuple[Union[int, str], ...]
19
- COMMIT_ID = Union[str, None]
20
- else:
21
- VERSION_TUPLE = object
22
- COMMIT_ID = object
23
-
24
- version: str
25
- __version__: str
26
- __version_tuple__: VERSION_TUPLE
27
- version_tuple: VERSION_TUPLE
28
- commit_id: COMMIT_ID
29
- __commit_id__: COMMIT_ID
30
-
31
- __version__ = version = '0.2.2'
32
- __version_tuple__ = version_tuple = (0, 2, 2)
33
-
34
- __commit_id__ = commit_id = None
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes