@danmoisan/drm-copilot-mcp 0.0.6 → 1.0.0
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.
- package/out/mcp-server.js +10213 -398
- package/package.json +2 -2
- package/resources/claude-customizations/.claude/hooks/enforce-completion-consistency.ps1 +127 -17
- package/resources/claude-customizations/.claude/hooks/enforce-completion-helpers.ps1 +163 -0
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +0 -12
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +68 -1
- package/resources/config/orchestration-routing.json +3 -3
- package/resources/codex-and-agents-customizations/.codex/scripts/post-codex-worktree-session.ps1 +0 -5
- package/resources/scripts/dev_tools/__init__.py +0 -0
- package/resources/scripts/dev_tools/_orchestrator_state_human_interaction.py +0 -127
- package/resources/scripts/dev_tools/_orchestrator_state_routing.py +0 -216
- package/resources/scripts/dev_tools/agentic_sync.py +0 -819
- package/resources/scripts/dev_tools/codex_native_converter/__init__.py +0 -11
- package/resources/scripts/dev_tools/codex_native_converter/__main__.py +0 -6
- package/resources/scripts/dev_tools/codex_native_converter/cli.py +0 -11
- package/resources/scripts/dev_tools/new_active_feature_folder.py +0 -79
- package/resources/scripts/dev_tools/new_active_feature_folder_docs.py +0 -268
- package/resources/scripts/dev_tools/new_active_feature_folder_flow.py +0 -366
- package/resources/scripts/dev_tools/new_active_feature_folder_io.py +0 -306
- package/resources/scripts/dev_tools/new_active_feature_folder_markdown.py +0 -252
- package/resources/scripts/dev_tools/new_active_feature_folder_models.py +0 -136
- package/resources/scripts/dev_tools/new_potential_bug_entry.py +0 -465
- package/resources/scripts/dev_tools/potential_to_issue.py +0 -421
- package/resources/scripts/dev_tools/potential_to_issue_content.py +0 -212
- package/resources/scripts/dev_tools/pr_context/__init__.py +0 -0
- package/resources/scripts/dev_tools/pr_context/collector.py +0 -619
- package/resources/scripts/dev_tools/pr_context/feature_docs.py +0 -349
- package/resources/scripts/dev_tools/pr_context/git.py +0 -153
- package/resources/scripts/dev_tools/pr_context/github.py +0 -549
- package/resources/scripts/dev_tools/pr_context/models.py +0 -198
- package/resources/scripts/dev_tools/pr_context/render.py +0 -342
- package/resources/scripts/dev_tools/pr_context/render_feature_excerpts.py +0 -256
- package/resources/scripts/dev_tools/pr_context/render_pr_helpers.py +0 -291
- package/resources/scripts/dev_tools/pr_context/summary_helpers.py +0 -386
- package/resources/scripts/dev_tools/pr_context/verification_evidence.py +0 -171
- package/resources/scripts/dev_tools/prompt_mode_contract.py +0 -152
- package/resources/scripts/dev_tools/push_down_claude_customizations.py +0 -403
- package/resources/scripts/dev_tools/push_down_claude_filesystem.py +0 -472
- package/resources/scripts/dev_tools/push_down_claude_pack_selection.py +0 -401
- package/resources/scripts/dev_tools/push_down_codex_and_agents_customizations.py +0 -139
- package/resources/scripts/dev_tools/push_down_copilot_customizations.py +0 -504
- package/resources/scripts/dev_tools/push_down_copilot_customizations_filesystem.py +0 -217
- package/resources/scripts/dev_tools/push_down_copilot_customizations_rewrites.py +0 -293
- package/resources/scripts/dev_tools/resolve_file_prompt.py +0 -457
- package/resources/scripts/dev_tools/resolve_hard_lock_prompt.py +0 -444
- package/resources/scripts/dev_tools/validate_orchestration_artifacts.py +0 -246
- package/resources/scripts/dev_tools/validate_orchestration_review_artifacts.py +0 -107
- package/resources/scripts/dev_tools/validate_orchestrator_state.py +0 -505
- package/resources/scripts/dev_tools/validate_policy_audit_artifact.py +0 -472
- package/resources/templates/codex_native_converter.py +0 -35
- package/resources/templates/collect_commit_context.py +0 -212
- package/resources/templates/collect_pr_context.py +0 -74
- package/resources/templates/hello_python.py +0 -11
- package/resources/templates/new_active_feature_folder.py +0 -67
- package/resources/templates/new_potential_bug_entry.py +0 -54
- package/resources/templates/potential_to_issue.py +0 -55
- package/resources/templates/push_down_claude_customizations.py +0 -233
- package/resources/templates/push_down_codex_and_agents_customizations.py +0 -95
- package/resources/templates/push_down_copilot_customizations.py +0 -124
- package/resources/templates/resolve_atomic_plan_prompt.py +0 -75
- package/resources/templates/resolve_hard_lock_prompt.py +0 -65
- package/resources/templates/validate_orchestration_artifacts.py +0 -55
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
"""Routing and mandatory handoff invariants for orchestrator checkpoints."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import json
|
|
6
|
-
from pathlib import Path
|
|
7
|
-
from typing import Any, cast
|
|
8
|
-
|
|
9
|
-
ROUTING_MATRIX_PATH = (
|
|
10
|
-
Path(__file__).resolve().parents[2] / "config" / "orchestration-routing.json"
|
|
11
|
-
)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def load_routing_matrix(path: Path = ROUTING_MATRIX_PATH) -> dict[str, Any]:
|
|
15
|
-
"""Load the repository routing matrix from disk."""
|
|
16
|
-
|
|
17
|
-
loaded: object = json.loads(path.read_text(encoding="utf-8"))
|
|
18
|
-
return cast("dict[str, Any]", loaded)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def _string_list(value: object) -> list[str] | None:
|
|
22
|
-
"""Return a list of strings only when the value has that exact shape."""
|
|
23
|
-
|
|
24
|
-
if not isinstance(value, list):
|
|
25
|
-
return None
|
|
26
|
-
values = cast("list[object]", value)
|
|
27
|
-
if not all(isinstance(item, str) and item.strip() for item in values):
|
|
28
|
-
return None
|
|
29
|
-
return cast("list[str]", values)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def _route_list(route: dict[str, Any], key: str) -> list[str]:
|
|
33
|
-
"""Read a required string-list field from one route entry."""
|
|
34
|
-
|
|
35
|
-
value = _string_list(route.get(key))
|
|
36
|
-
return [] if value is None else value
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def _state_list(
|
|
40
|
-
state: dict[str, Any], key: str, route_id: str, expected: list[str]
|
|
41
|
-
) -> list[str] | None:
|
|
42
|
-
"""Validate a state list against the routing matrix list."""
|
|
43
|
-
|
|
44
|
-
value = _string_list(state.get(key))
|
|
45
|
-
if value is None:
|
|
46
|
-
return None
|
|
47
|
-
if value != expected:
|
|
48
|
-
return None
|
|
49
|
-
return value
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def _list_receipts(receipts: object) -> list[dict[str, Any]]:
|
|
53
|
-
"""Return legacy list delegation receipts as typed dictionaries."""
|
|
54
|
-
|
|
55
|
-
if not isinstance(receipts, list):
|
|
56
|
-
return []
|
|
57
|
-
receipt_list = cast("list[object]", receipts)
|
|
58
|
-
return [
|
|
59
|
-
cast("dict[str, Any]", item) for item in receipt_list if isinstance(item, dict)
|
|
60
|
-
]
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def _receipt_agents(state: dict[str, Any]) -> set[str]:
|
|
64
|
-
"""Collect agent names from delegation receipts."""
|
|
65
|
-
|
|
66
|
-
agents: set[str] = set()
|
|
67
|
-
for receipt in _list_receipts(state.get("delegation_receipts")):
|
|
68
|
-
agent_name = receipt.get("agent_name")
|
|
69
|
-
if isinstance(agent_name, str) and agent_name.strip():
|
|
70
|
-
agents.add(agent_name)
|
|
71
|
-
return agents
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def _receipt_skills(state: dict[str, Any]) -> set[str]:
|
|
75
|
-
"""Collect acknowledged skill names from skill receipts."""
|
|
76
|
-
|
|
77
|
-
skills: set[str] = set()
|
|
78
|
-
receipts = state.get("skill_receipts")
|
|
79
|
-
if not isinstance(receipts, list):
|
|
80
|
-
return skills
|
|
81
|
-
for receipt in cast("list[object]", receipts):
|
|
82
|
-
if not isinstance(receipt, dict):
|
|
83
|
-
continue
|
|
84
|
-
receipt_map = cast("dict[str, object]", receipt)
|
|
85
|
-
skill = receipt_map.get("skill")
|
|
86
|
-
required = receipt_map.get("required")
|
|
87
|
-
evidence = receipt_map.get("evidence")
|
|
88
|
-
if (
|
|
89
|
-
isinstance(skill, str)
|
|
90
|
-
and skill.strip()
|
|
91
|
-
and required is True
|
|
92
|
-
and isinstance(evidence, str)
|
|
93
|
-
and evidence.strip()
|
|
94
|
-
):
|
|
95
|
-
skills.add(skill)
|
|
96
|
-
return skills
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
def _mcp_tools(state: dict[str, Any]) -> set[str]:
|
|
100
|
-
"""Collect successful MCP tool receipts from checkpoint state."""
|
|
101
|
-
|
|
102
|
-
tools: set[str] = set()
|
|
103
|
-
receipts = state.get("mcp_call_receipts")
|
|
104
|
-
if not isinstance(receipts, list):
|
|
105
|
-
return tools
|
|
106
|
-
for receipt in cast("list[object]", receipts):
|
|
107
|
-
if not isinstance(receipt, dict):
|
|
108
|
-
continue
|
|
109
|
-
receipt_map = cast("dict[str, object]", receipt)
|
|
110
|
-
tool = receipt_map.get("tool")
|
|
111
|
-
ok = receipt_map.get("ok")
|
|
112
|
-
evidence = receipt_map.get("evidence")
|
|
113
|
-
if (
|
|
114
|
-
isinstance(tool, str)
|
|
115
|
-
and tool.strip()
|
|
116
|
-
and ok is True
|
|
117
|
-
and isinstance(evidence, str)
|
|
118
|
-
and evidence.strip()
|
|
119
|
-
):
|
|
120
|
-
tools.add(tool)
|
|
121
|
-
return tools
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
def _validate_empty_list_field(state: dict[str, Any], key: str) -> list[str]:
|
|
125
|
-
"""Require a checkpoint field to exist as an empty list."""
|
|
126
|
-
|
|
127
|
-
value = state.get(key)
|
|
128
|
-
if not isinstance(value, list):
|
|
129
|
-
return [f"Checkpoint {key} must be an empty list at completion."]
|
|
130
|
-
if value:
|
|
131
|
-
return [f"Checkpoint {key} must be empty at completion."]
|
|
132
|
-
return []
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
def _validate_lifecycle_operations(state: dict[str, Any]) -> list[str]:
|
|
136
|
-
"""Reject lifecycle-operation records that did not use MCP."""
|
|
137
|
-
|
|
138
|
-
operations = state.get("lifecycle_operations")
|
|
139
|
-
if operations is None:
|
|
140
|
-
return []
|
|
141
|
-
if not isinstance(operations, list):
|
|
142
|
-
return ["Checkpoint lifecycle_operations must be a list when present."]
|
|
143
|
-
errors: list[str] = []
|
|
144
|
-
for index, operation in enumerate(cast("list[object]", operations)):
|
|
145
|
-
if not isinstance(operation, dict):
|
|
146
|
-
errors.append(
|
|
147
|
-
f"Checkpoint lifecycle_operations #{index} must be an object."
|
|
148
|
-
)
|
|
149
|
-
continue
|
|
150
|
-
operation_map = cast("dict[str, object]", operation)
|
|
151
|
-
if operation_map.get("surface") != "mcp":
|
|
152
|
-
errors.append(
|
|
153
|
-
f"Checkpoint lifecycle_operations #{index} did not use MCP surface."
|
|
154
|
-
)
|
|
155
|
-
return errors
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
def validate_routing_contract(
|
|
159
|
-
state: dict[str, Any], *, routing_matrix: dict[str, Any] | None = None
|
|
160
|
-
) -> list[str]:
|
|
161
|
-
"""Validate mandatory route, handoff, skill, and MCP completion evidence."""
|
|
162
|
-
|
|
163
|
-
matrix = routing_matrix if routing_matrix is not None else load_routing_matrix()
|
|
164
|
-
raw_routes = matrix.get("routes")
|
|
165
|
-
if not isinstance(raw_routes, dict):
|
|
166
|
-
return ["Routing matrix missing routes object."]
|
|
167
|
-
routes = cast("dict[str, object]", raw_routes)
|
|
168
|
-
|
|
169
|
-
route_id = state.get("route_id", state.get("path_selected"))
|
|
170
|
-
if not isinstance(route_id, str) or not route_id.strip():
|
|
171
|
-
return ["Checkpoint route_id or path_selected must select a route."]
|
|
172
|
-
raw_route = routes.get(route_id)
|
|
173
|
-
if not isinstance(raw_route, dict):
|
|
174
|
-
return [f"Checkpoint selected route has no routing-matrix entry: {route_id}."]
|
|
175
|
-
route_map = cast("dict[str, Any]", raw_route)
|
|
176
|
-
|
|
177
|
-
errors: list[str] = []
|
|
178
|
-
required_agents = _route_list(route_map, "required_agents")
|
|
179
|
-
required_skills = _route_list(route_map, "required_skills")
|
|
180
|
-
required_mcp_tools = _route_list(route_map, "required_mcp_tools")
|
|
181
|
-
|
|
182
|
-
if _state_list(state, "required_agents", route_id, required_agents) is None:
|
|
183
|
-
errors.append(
|
|
184
|
-
"Checkpoint required_agents must match routing matrix for route "
|
|
185
|
-
f"{route_id}."
|
|
186
|
-
)
|
|
187
|
-
if _state_list(state, "required_skills", route_id, required_skills) is None:
|
|
188
|
-
errors.append(
|
|
189
|
-
"Checkpoint required_skills must match routing matrix for route "
|
|
190
|
-
f"{route_id}."
|
|
191
|
-
)
|
|
192
|
-
if _state_list(state, "required_mcp_tools", route_id, required_mcp_tools) is None:
|
|
193
|
-
errors.append(
|
|
194
|
-
"Checkpoint required_mcp_tools must match routing matrix for route "
|
|
195
|
-
f"{route_id}."
|
|
196
|
-
)
|
|
197
|
-
|
|
198
|
-
actual_agents = _receipt_agents(state)
|
|
199
|
-
for agent in required_agents:
|
|
200
|
-
if agent not in actual_agents:
|
|
201
|
-
errors.append(f"Checkpoint missing required agent receipt: {agent}.")
|
|
202
|
-
|
|
203
|
-
actual_skills = _receipt_skills(state)
|
|
204
|
-
for skill in required_skills:
|
|
205
|
-
if skill not in actual_skills:
|
|
206
|
-
errors.append(f"Checkpoint missing required skill receipt: {skill}.")
|
|
207
|
-
|
|
208
|
-
actual_tools = _mcp_tools(state)
|
|
209
|
-
for tool in required_mcp_tools:
|
|
210
|
-
if tool not in actual_tools:
|
|
211
|
-
errors.append(f"Checkpoint missing successful MCP receipt: {tool}.")
|
|
212
|
-
|
|
213
|
-
errors.extend(_validate_empty_list_field(state, "local_execution_overrides"))
|
|
214
|
-
errors.extend(_validate_empty_list_field(state, "delegation_bypasses"))
|
|
215
|
-
errors.extend(_validate_lifecycle_operations(state))
|
|
216
|
-
return errors
|