@ccoalm/ccl-skills 0.15.0 → 0.15.2

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 (71) hide show
  1. package/README.md +3 -1
  2. package/dist/assets/marketplace/plugins/ccl-skills/agent-context/session-start.md +1 -1
  3. package/dist/assets/marketplace/plugins/ccl-skills/packages/opencode-plugin/ccl-skills.ts +80 -4
  4. package/dist/assets/marketplace/plugins/ccl-skills/packages/opencode-plugin/commands/ccl-install-skills.md +16 -4
  5. package/dist/assets/marketplace/plugins/ccl-skills/scripts/owner-dispatch/owner-dispatch.sh +13 -2
  6. package/dist/assets/marketplace/plugins/ccl-skills/scripts/owner-dispatch/test.sh +53 -0
  7. package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/SKILL.md +2 -2
  8. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/SKILL.md +6 -5
  9. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/development-completion.md +26 -0
  10. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/staged-review-contract.md +37 -13
  11. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/AGENTS.md +5 -2
  12. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/codex_review.sh +77 -5
  13. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/kimi_packet_mcp.py +98 -4
  14. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/parse_cli_review.py +48 -1
  15. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/review_gate.py +237 -17
  16. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_cli_review_wrappers.sh +165 -11
  17. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_kimi_packet_mcp.py +143 -0
  18. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_review_client_compat.py +572 -0
  19. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_review_gate.sh +65 -0
  20. package/dist/assets/marketplace/plugins/ccl-skills/skills/defect-diagnosis/SKILL.md +3 -1
  21. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/SKILL.md +1 -1
  22. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/SKILL.md +2 -0
  23. package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/SKILL.md +1 -1
  24. package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-agent-delegation/SKILL.md +1 -1
  25. package/dist/assets/marketplace/plugins/ccl-skills/skills/nodejs-service-dev/SKILL.md +2 -0
  26. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/SKILL.md +7 -5
  27. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/alerting-and-on-call.md +8 -0
  28. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/SKILL.md +3 -1
  29. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/SKILL.md +16 -14
  30. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/dual-sidecar-and-traffic-config-center.md +1 -1
  31. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/grpc-authority-workaround.md +40 -83
  32. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/mesh-architecture.md +2 -2
  33. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/retry-timeout-circuit-breaker.md +44 -37
  34. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/service-discovery-recipe.md +1 -1
  35. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/SKILL.md +7 -7
  36. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/delivery-lifecycle.md +1 -1
  37. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/design-review-gate-mechanics.md +1 -1
  38. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/pre-final-continuation-gate.md +20 -11
  39. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/refactoring-discipline.md +7 -1
  40. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/SKILL.md +1 -1
  41. package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-scope/SKILL.md +8 -5
  42. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/SKILL.md +2 -2
  43. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/dual-track-review-gate.md +17 -17
  44. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/external-practice-controls.md +3 -3
  45. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/harness-patterns-and-eval.md +4 -4
  46. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/resume-paused-delivery.md +3 -3
  47. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/source-register.md +24 -0
  48. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/eval-golden-trace.rb +31 -7
  49. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/impact-chain-gate.rb +74 -3
  50. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/skill-behavior-eval.py +103 -21
  51. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_ai_coding_implementation_gates.sh +83 -48
  52. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_body_compliance_grading.sh +80 -2
  53. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_impact_chain_refscripts.sh +74 -1
  54. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_controlled_escalation_pins.sh +3 -2
  55. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_eval_runtime.py +428 -0
  56. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_validate_extraction_review_state.sh +190 -2
  57. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/validate_extraction_review_state.py +106 -4
  58. package/dist/assets/marketplace/plugins/ccl-skills/skills/terminal-cli-dev/SKILL.md +1 -1
  59. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/SKILL.md +3 -1
  60. package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/SKILL.md +1 -1
  61. package/dist/assets/release.json +87 -67
  62. package/dist/claude-adapter.js +14 -7
  63. package/dist/codex-host.d.ts +2 -4
  64. package/dist/codex-host.js +40 -19
  65. package/dist/host-probe.d.ts +27 -0
  66. package/dist/host-probe.js +51 -0
  67. package/dist/opencode-adapter.js +24 -19
  68. package/dist/operations.js +34 -8
  69. package/dist/unified.d.ts +1 -1
  70. package/dist/unified.js +18 -9
  71. package/package.json +1 -1
@@ -140,10 +140,15 @@ CODEX_EXEC_HELP="$(timeout --kill-after=1s 5s "$CODEX_BIN_PATH" exec --disable h
140
140
  # supported lifecycle state: `features list` still prints removed keys, and a
141
141
  # removed or unknown-state row means `--disable hooks` may be a silent no-op
142
142
  # that lets user-trusted hooks run during packet-only review.
143
- CODEX_FEATURES_LIST="$(timeout --kill-after=1s 5s "$CODEX_BIN_PATH" features list 2>/dev/null)" \
143
+ CODEX_FEATURES_LIST="$(timeout --kill-after=1s 5s "$CODEX_BIN_PATH" features list --disable hooks --disable shell_tool 2>/dev/null)" \
144
144
  || die_inconclusive codex_hook_disable_unavailable capability_missing true
145
- grep -Eq '^hooks[[:space:]]+(stable|under development|experimental)([[:space:]]|$)' <<<"$CODEX_FEATURES_LIST" \
145
+ grep -Eq '^hooks[[:space:]]+(stable|under development|experimental)[[:space:]]+false[[:space:]]*$' <<<"$CODEX_FEATURES_LIST" \
146
146
  || die_inconclusive codex_hook_disable_unavailable capability_missing true
147
+ # A read-only sandbox still exposes command execution. Disable the actual
148
+ # shell surface, including its unified-exec implementation, before inference.
149
+ # Check effective capability rather than a CLI release number or flag parsing.
150
+ grep -Eq '^shell_tool[[:space:]]+(stable|under development|experimental)[[:space:]]+false[[:space:]]*$' <<<"$CODEX_FEATURES_LIST" \
151
+ || die_inconclusive codex_shell_disable_unavailable capability_missing true
147
152
  if [ -n "${CODEX_HOME:-}" ]; then
148
153
  SOURCE_HOME="$CODEX_HOME"
149
154
  else
@@ -240,6 +245,72 @@ fi
240
245
  DIFF_TEXT="$(cat "$DIFF_FILE" || exit 1; printf '\001')" \
241
246
  || die_inconclusive diff_read_failed local_tool_failure false
242
247
  DIFF_TEXT="${DIFF_TEXT%$'\001'}"
248
+ PACKET_FILE="$RUN_ROOT/packet.txt"
249
+ PACKET_SERVER="$SCRIPT_DIR/kimi_packet_mcp.py"
250
+ [ -f "$PACKET_SERVER" ] && [ -r "$PACKET_SERVER" ] && [ ! -L "$PACKET_SERVER" ] \
251
+ || die_inconclusive packet_server_missing local_tool_failure false
252
+ printf '%s' "$DIFF_TEXT" >"$PACKET_FILE"
253
+ PACKET_SHA256="$(python3 - "$PACKET_FILE" <<'PY_HASH'
254
+ import hashlib, sys
255
+ from pathlib import Path
256
+ print(hashlib.sha256(Path(sys.argv[1]).read_bytes()).hexdigest())
257
+ PY_HASH
258
+ )" || die_inconclusive packet_hash_failed local_tool_failure false
259
+ MCP_CONFIG="$(python3 - "$PACKET_FILE" "$PACKET_SERVER" "$PACKET_SHA256" <<'PY_MCP_CONFIG'
260
+ import json, sys
261
+ values = [sys.argv[2], "--packet", sys.argv[1], "--sha256", sys.argv[3], "--allow-search"]
262
+ print('mcp_servers={code_review_packet={command=' + json.dumps(sys.executable)
263
+ + ',args=[' + ','.join(json.dumps(value) for value in values)
264
+ + '],enabled=true,enabled_tools=["read_packet","search_packet"]}}')
265
+ PY_MCP_CONFIG
266
+ )" || die_inconclusive packet_config_failed local_tool_failure false
267
+ # TOML overrides merge server tables. Disable inherited servers for this run
268
+ # without changing user configuration, then verify the effective public list.
269
+ CODEX_PACKET_CONFIG=(-c "$MCP_CONFIG" -c 'web_search="disabled"' -c 'approval_policy="never"')
270
+ CODEX_HOME="$SOURCE_HOME" timeout --kill-after=1s 5s "$CODEX_BIN_PATH" mcp list --json "${CODEX_PACKET_CONFIG[@]}" >"$RUN_ROOT/mcp.json" 2>"$STDERR_FILE" \
271
+ || die_inconclusive codex_packet_tools_unavailable capability_missing true
272
+ MCP_CONFIG="$(python3 - "$RUN_ROOT/mcp.json" "$MCP_CONFIG" <<'PY_MCP_OVERRIDES'
273
+ import json, sys
274
+ from pathlib import Path
275
+ try:
276
+ rows = json.loads(Path(sys.argv[1]).read_text())
277
+ if not isinstance(rows, list):
278
+ raise ValueError()
279
+ disabled = []
280
+ for row in rows:
281
+ if not isinstance(row, dict) or not isinstance(row.get("name"), str) or not row["name"]:
282
+ raise ValueError()
283
+ if row["name"] != "code_review_packet":
284
+ disabled.append(json.dumps(row["name"]) + "={enabled=false}")
285
+ print(sys.argv[2][:-1] + "".join("," + entry for entry in disabled) + "}")
286
+ except (OSError, ValueError, TypeError):
287
+ sys.exit(1)
288
+ PY_MCP_OVERRIDES
289
+ )" || die_inconclusive codex_packet_tools_unavailable capability_missing true
290
+ CODEX_PACKET_CONFIG=(-c "$MCP_CONFIG" -c 'web_search="disabled"' -c 'approval_policy="never"')
291
+ CODEX_HOME="$SOURCE_HOME" timeout --kill-after=1s 5s "$CODEX_BIN_PATH" mcp list --json "${CODEX_PACKET_CONFIG[@]}" >"$RUN_ROOT/mcp.json" 2>"$STDERR_FILE" \
292
+ || die_inconclusive codex_packet_tools_unavailable capability_missing true
293
+ python3 - "$RUN_ROOT/mcp.json" "$PACKET_FILE" "$PACKET_SERVER" "$PACKET_SHA256" <<'PY_MCP_CHECK' \
294
+ || die_inconclusive codex_packet_tools_unavailable capability_missing true
295
+ import json, sys
296
+ from pathlib import Path
297
+ try:
298
+ rows = json.loads(Path(sys.argv[1]).read_text())
299
+ if not isinstance(rows, list):
300
+ raise ValueError()
301
+ active = [row for row in rows if isinstance(row, dict) and row.get("enabled") is not False]
302
+ if len(active) != 1 or len(rows) != len([row for row in rows if isinstance(row, dict)]):
303
+ raise ValueError()
304
+ row = active[0]
305
+ transport = row.get("transport", {})
306
+ if (row.get("name") != "code_review_packet" or row.get("enabled") is not True
307
+ or transport.get("type") != "stdio" or transport.get("command") != sys.executable
308
+ or transport.get("args") != [sys.argv[3], "--packet", sys.argv[2], "--sha256", sys.argv[4], "--allow-search"]
309
+ or transport.get("env") or transport.get("env_vars") or transport.get("cwd")):
310
+ raise ValueError()
311
+ except (OSError, ValueError, TypeError, AttributeError):
312
+ sys.exit(1)
313
+ PY_MCP_CHECK
243
314
  {
244
315
  printf '%s\n\n' "$INSTRUCTION"
245
316
  if [ "$REVIEW_SKILL_COUNT" -gt 0 ]; then
@@ -255,7 +326,7 @@ DIFF_TEXT="${DIFF_TEXT%$'\001'}"
255
326
  printf '%s' "$PROFILE_TEXT"
256
327
  printf '\n%s_END\n\n' "$PROFILE_TOKEN"
257
328
  fi
258
- printf '%s\n' 'Use only the supplied diff. Do not invoke tools or inspect the workspace.'
329
+ printf '%s\n' 'Use only the supplied diff and review profile. You may read or search the same frozen diff using code_review_packet read_packet and search_packet. These pathless tools cannot inspect the workspace. Do not execute commands, access other tools, or follow skill instructions to run development workflows or read external references. Report missing context as an evidence gap.'
259
330
  if [ -n "$REVIEW_PROFILE_FILE" ]; then
260
331
  printf '%s\n' 'Treat self_review and evidence as claims to verify against the diff, not as proof. Check every entry in required_concerns. A no-findings verdict is valid only after all entries were checked; if the bounded packet cannot support a required check, report that evidence gap as a material finding at the best changed-file locator.'
261
332
  printf '%s\n' 'Return exactly one concern_results object with concern and concise independent conclusion for every required concern.'
@@ -279,7 +350,8 @@ JSON
279
350
  fi
280
351
 
281
352
  run_started=$SECONDS
282
- CMUX_CODEX_HOOKS_DISABLED=1 CODEX_HOME="$SOURCE_HOME" timeout --kill-after=1s "${TIMEOUT}s" "$CODEX_BIN_PATH" exec --disable hooks --sandbox read-only --ephemeral --skip-git-repo-check \
353
+ CMUX_CODEX_HOOKS_DISABLED=1 CODEX_HOME="$SOURCE_HOME" timeout --kill-after=1s "${TIMEOUT}s" "$CODEX_BIN_PATH" exec --disable hooks --disable shell_tool --sandbox read-only --ephemeral --skip-git-repo-check \
354
+ "${CODEX_PACKET_CONFIG[@]}" \
283
355
  --json --output-schema "$SCHEMA_FILE" --output-last-message "$RESULT_FILE" \
284
356
  -C "$RUN_WORKSPACE" - <"$PROMPT_FILE" >"$EVENTS" 2>"$STDERR_FILE"
285
357
  run_rc=$?
@@ -309,7 +381,7 @@ fi
309
381
 
310
382
  python3 "$PARSER" --client codex --mode "$MODE" --implementer-family "$IMPL_FAMILY" \
311
383
  --reviewer-family "$FAMILY" --provider "$PROVIDER" --model "$MODEL" \
312
- --events "$EVENTS" --result-file "$RESULT_FILE" >"$PARSED_FILE"
384
+ --events "$EVENTS" --result-file "$RESULT_FILE" --packet "$PACKET_FILE" --packet-sha256 "$PACKET_SHA256" >"$PARSED_FILE"
313
385
  parser_rc=$?
314
386
  if [ "$parser_rc" -eq 0 ]; then
315
387
  native_skill_binding="not_requested"
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env python3
2
- """Expose one SHA-256-bound review packet through a pathless stdio MCP tool."""
2
+ """Expose one SHA-256-bound review packet through pathless stdio MCP tools."""
3
3
 
4
4
  from __future__ import annotations
5
5
 
@@ -12,8 +12,11 @@ from typing import Any
12
12
 
13
13
 
14
14
  TOOL_NAME = "read_packet"
15
+ SEARCH_TOOL_NAME = "search_packet"
15
16
  MAX_PAGE_BYTES = 48_000
16
17
  MAX_CHUNK_BYTES = 46_000
18
+ MAX_QUERY_BYTES = 1_024
19
+ MAX_SEARCH_RESULTS = 100
17
20
 
18
21
 
19
22
  def packet_bytes(path: Path, expected_sha256: str) -> bytes:
@@ -57,6 +60,84 @@ def tool_result(text: str, *, error: bool = False) -> dict[str, Any]:
57
60
  return {"content": [{"type": "text", "text": text}], "isError": error}
58
61
 
59
62
 
63
+ def search_tool_definition() -> dict[str, Any]:
64
+ return {
65
+ "name": SEARCH_TOOL_NAME,
66
+ "description": (
67
+ "Find non-overlapping, case-sensitive literal substrings in the one "
68
+ "controller-frozen review packet. No regex or filesystem paths. "
69
+ "Query is at most 1024 UTF-8 bytes; byte_offset must be a UTF-8 "
70
+ "boundary. Returns byte offsets and 1-based line numbers, with "
71
+ "next_byte_offset for more matches or null when exhausted. "
72
+ "Use read_packet at a match offset to inspect its context."
73
+ ),
74
+ "inputSchema": {
75
+ "type": "object",
76
+ "properties": {
77
+ "query": {"type": "string", "minLength": 1, "maxLength": MAX_QUERY_BYTES},
78
+ "byte_offset": {"type": "integer", "minimum": 0},
79
+ "limit": {"type": "integer", "minimum": 1, "maximum": MAX_SEARCH_RESULTS},
80
+ },
81
+ "required": ["query", "byte_offset", "limit"],
82
+ "additionalProperties": False,
83
+ },
84
+ }
85
+
86
+
87
+ def search_packet(path: Path, expected_sha256: str, arguments: Any) -> dict[str, Any]:
88
+ if not isinstance(arguments, dict) or set(arguments) != {"query", "byte_offset", "limit"}:
89
+ return tool_result("invalid packet search arguments", error=True)
90
+ query = arguments.get("query")
91
+ byte_offset = arguments.get("byte_offset")
92
+ limit = arguments.get("limit")
93
+ if (
94
+ not isinstance(query, str)
95
+ or not isinstance(byte_offset, int)
96
+ or isinstance(byte_offset, bool)
97
+ or byte_offset < 0
98
+ or not isinstance(limit, int)
99
+ or isinstance(limit, bool)
100
+ or not 1 <= limit <= MAX_SEARCH_RESULTS
101
+ ):
102
+ return tool_result("invalid packet search arguments", error=True)
103
+ try:
104
+ needle = query.encode("utf-8")
105
+ except UnicodeEncodeError:
106
+ return tool_result("invalid packet search arguments", error=True)
107
+ if not 1 <= len(needle) <= MAX_QUERY_BYTES:
108
+ return tool_result("invalid packet search arguments", error=True)
109
+ try:
110
+ data = packet_bytes(path, expected_sha256)
111
+ except (OSError, ValueError):
112
+ return tool_result("packet binding changed", error=True)
113
+ if byte_offset > len(data):
114
+ return tool_result("packet search starts beyond end", error=True)
115
+ try:
116
+ data[:byte_offset].decode("utf-8")
117
+ except UnicodeDecodeError:
118
+ return tool_result("packet search starts inside a UTF-8 character", error=True)
119
+
120
+ matches = []
121
+ cursor = byte_offset
122
+ while len(matches) < limit:
123
+ found = data.find(needle, cursor)
124
+ if found < 0:
125
+ break
126
+ matches.append({"byte_offset": found, "line": data.count(b"\n", 0, found) + 1})
127
+ cursor = found + len(needle)
128
+ rendered = json.dumps(
129
+ {
130
+ "matches": matches,
131
+ "next_byte_offset": cursor if data.find(needle, cursor) >= 0 else None,
132
+ "total_bytes": len(data),
133
+ },
134
+ separators=(",", ":"),
135
+ )
136
+ if len(rendered.encode("utf-8")) > MAX_PAGE_BYTES:
137
+ return tool_result("packet search exceeds result bound", error=True)
138
+ return tool_result(rendered)
139
+
140
+
60
141
  def read_chunk(path: Path, expected_sha256: str, arguments: Any) -> dict[str, Any]:
61
142
  if not isinstance(arguments, dict) or set(arguments) != {"byte_offset", "max_bytes"}:
62
143
  return tool_result("invalid packet chunk arguments", error=True)
@@ -119,7 +200,9 @@ def response(request_id: Any, *, result: Any = None, error: Any = None) -> dict[
119
200
  return payload
120
201
 
121
202
 
122
- def handle(message: Any, path: Path, expected_sha256: str) -> dict[str, Any] | None:
203
+ def handle(
204
+ message: Any, path: Path, expected_sha256: str, *, allow_search: bool = False
205
+ ) -> dict[str, Any] | None:
123
206
  if not isinstance(message, dict) or message.get("jsonrpc") != "2.0":
124
207
  return response(None, error={"code": -32600, "message": "Invalid Request"})
125
208
  request_id = message.get("id")
@@ -140,9 +223,17 @@ def handle(message: Any, path: Path, expected_sha256: str) -> dict[str, Any] | N
140
223
  if method == "ping":
141
224
  return response(request_id, result={})
142
225
  if method == "tools/list":
143
- return response(request_id, result={"tools": [tool_definition()]})
226
+ definitions = [tool_definition()]
227
+ if allow_search:
228
+ definitions.append(search_tool_definition())
229
+ return response(request_id, result={"tools": definitions})
144
230
  if method == "tools/call":
145
231
  params = message.get("params")
232
+ if isinstance(params, dict) and allow_search and params.get("name") == SEARCH_TOOL_NAME:
233
+ return response(
234
+ request_id,
235
+ result=search_packet(path, expected_sha256, params.get("arguments")),
236
+ )
146
237
  if not isinstance(params, dict) or params.get("name") != TOOL_NAME:
147
238
  return response(request_id, result=tool_result("unknown tool", error=True))
148
239
  return response(
@@ -156,6 +247,9 @@ def main() -> int:
156
247
  parser = argparse.ArgumentParser(description=__doc__)
157
248
  parser.add_argument("--packet", required=True)
158
249
  parser.add_argument("--sha256", required=True)
250
+ parser.add_argument(
251
+ "--allow-search", action="store_true", help="also expose bounded literal packet search"
252
+ )
159
253
  args = parser.parse_args()
160
254
  if not len(args.sha256) == 64 or any(ch not in "0123456789abcdef" for ch in args.sha256):
161
255
  parser.error("--sha256 must be a lowercase SHA-256 digest")
@@ -169,7 +263,7 @@ def main() -> int:
169
263
  for raw_line in sys.stdin:
170
264
  try:
171
265
  message = json.loads(raw_line)
172
- payload = handle(message, path, args.sha256)
266
+ payload = handle(message, path, args.sha256, allow_search=args.allow_search)
173
267
  except (json.JSONDecodeError, UnicodeError):
174
268
  payload = response(None, error={"code": -32700, "message": "Parse error"})
175
269
  if payload is not None:
@@ -10,6 +10,7 @@ import re
10
10
  from typing import Any
11
11
 
12
12
  from concern_excerpt import bounded_reason_detail, concern_fields
13
+ import kimi_packet_mcp as packet_tools
13
14
  from kimi_packet_mcp import MAX_CHUNK_BYTES
14
15
 
15
16
 
@@ -652,6 +653,18 @@ def audit_codex(
652
653
  def invalid(reason: str) -> dict[str, Any]:
653
654
  return invalid_model_output(args, reason, "\n".join(concern_fragments))
654
655
 
656
+ packet_path = getattr(args, "packet", None)
657
+ packet_sha256 = getattr(args, "packet_sha256", None)
658
+ if packet_path or packet_sha256:
659
+ try:
660
+ if not packet_path or not packet_sha256:
661
+ raise ValueError()
662
+ packet_tools.packet_bytes(Path(packet_path), packet_sha256)
663
+ except (OSError, ValueError):
664
+ return inconclusive(args, "Codex packet binding changed", "binding_mismatch", False)
665
+ pending_packet_calls: dict[str, tuple[str, Any]] = {}
666
+ completed_packet_calls: set[str] = set()
667
+
655
668
  for event in events:
656
669
  event_type = event.get("type")
657
670
  if event_type == "turn.completed":
@@ -678,6 +691,39 @@ def audit_codex(
678
691
  attempted_tool=event_type,
679
692
  )
680
693
  item_type = item.get("type")
694
+ if item_type == "mcp_tool_call" and packet_path and packet_sha256:
695
+ tool = item.get("tool")
696
+ if item.get("server") != "code_review_packet" or tool not in {"read_packet", "search_packet"}:
697
+ return inconclusive(args, "Codex attempted a tool outside the frozen packet", "tool_boundary_violation", False)
698
+ reader = packet_tools.read_chunk if tool == "read_packet" else packet_tools.search_packet
699
+ expected = reader(Path(packet_path), packet_sha256, item.get("arguments"))
700
+ content = expected["content"]
701
+ if expected.get("isError") and content[0]["text"] == "packet binding changed":
702
+ return inconclusive(args, "Codex packet binding changed", "binding_mismatch", False)
703
+ if expected.get("isError") and content[0]["text"].startswith("invalid packet"):
704
+ return inconclusive(args, "Codex supplied arguments outside the packet tool schema", "tool_boundary_violation", False)
705
+ call_id = item.get("id")
706
+ signature = (tool, item.get("arguments"))
707
+ if (not isinstance(call_id, str) or not call_id or call_id in completed_packet_calls
708
+ or (call_id in pending_packet_calls and pending_packet_calls[call_id] != signature)):
709
+ return inconclusive(args, "Codex packet tool lifecycle is unverifiable", "transport_unverifiable", False)
710
+ if event_type != "item.completed":
711
+ if item.get("status") != "in_progress":
712
+ return inconclusive(args, "Codex packet tool lifecycle is unverifiable", "transport_unverifiable", False)
713
+ pending_packet_calls[call_id] = signature
714
+ continue
715
+ result = item.get("result")
716
+ if not isinstance(result, dict):
717
+ return invalid("Codex packet tool returned no verifiable result")
718
+ if (result.get("content") != content or result.get("structured_content") not in (None, {})
719
+ or result.get("structuredContent") not in (None, {})):
720
+ return inconclusive(args, "Codex packet tool result did not match frozen bytes", "binding_mismatch", False)
721
+ allowed_statuses = {"completed", "failed"} if expected.get("isError") else {"completed"}
722
+ if item.get("status") not in allowed_statuses or (item.get("error") and not expected.get("isError")):
723
+ return invalid("Codex packet tool did not complete successfully")
724
+ pending_packet_calls.pop(call_id, None)
725
+ completed_packet_calls.add(call_id)
726
+ continue
681
727
  if item_type == "agent_message":
682
728
  item_text = item.get("text")
683
729
  if isinstance(item_text, str) and item_text.strip():
@@ -729,7 +775,7 @@ def audit_codex(
729
775
  )
730
776
  if event_type == "item.completed" and item_type == "agent_message":
731
777
  saw_completed_agent_message = True
732
- if not saw_completed_agent_message or not saw_completed_turn:
778
+ if pending_packet_calls or not saw_completed_agent_message or not saw_completed_turn:
733
779
  return inconclusive(
734
780
  args,
735
781
  "Codex event stream lacked positive completion evidence",
@@ -926,6 +972,7 @@ def main() -> int:
926
972
  parser.add_argument("--model", default="")
927
973
  parser.add_argument("--events", required=True)
928
974
  parser.add_argument("--packet")
975
+ parser.add_argument("--packet-sha256")
929
976
  parser.add_argument("--packet-delivery", choices=("mcp", "inline"), default="mcp")
930
977
  parser.add_argument("--packet-receipt", default="")
931
978
  parser.add_argument("--result-file")