cc-transcript 10.2.0__tar.gz → 10.3.0__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.
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/PKG-INFO +1 -1
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/mining/signals.py +1 -1
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/tools.py +23 -9
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/pyproject.toml +1 -1
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/rust/src/mining.rs +5 -1
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/Cargo.lock +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/Cargo.toml +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/LICENSE +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/README.md +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/__init__.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/__main__.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/_parser_rs.pyi +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/activity.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/activity_probe.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/backend.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/builders.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/cli.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/command.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/context.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/corrections.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/corrections_cli.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/cost.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/decisions.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/discovery.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/disktruth.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/evidence.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/extract/__init__.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/extract/correct.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/facts.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/filterspec.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/ids.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/judge/__init__.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/judge/llm.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/judge/similar.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/judge/verdicts.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/mining/__init__.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/mining/candidates.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/mining/confidence.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/mining/engine.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/mining/filterspec.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/mining/formats.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/mining/sourcekind.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/mining/spec.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/mining/store.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/models.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/notifications.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/parser.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/py.typed +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/query.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/render.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/rust.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/sentiment/__init__.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/sentiment/buckets.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/sentiment/engine.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/sentiment/lexicon.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/sentiment/scorespec.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/cc_transcript/store.py +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/rust/Cargo.toml +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/rust/build.rs +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/rust/data/afinn-en-165.tsv +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/rust/data/domain_overrides.tsv +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/rust/src/activity.rs +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/rust/src/command.rs +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/rust/src/event.rs +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/rust/src/filter.rs +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/rust/src/lexicon.rs +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/rust/src/lib.rs +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/rust/src/model.rs +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/rust/src/parse.rs +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/rust/src/protocol.rs +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/rust/src/python.rs +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/rust/src/score.rs +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/rust/src/types.rs +0 -0
- {cc_transcript-10.2.0 → cc_transcript-10.3.0}/rust/src/value.rs +0 -0
|
@@ -132,7 +132,7 @@ def last_edit_index(events: Sequence[TranscriptEvent], index: int, spec: MiningS
|
|
|
132
132
|
i
|
|
133
133
|
for i in range(index - 1, max(index - spec.reentry_lookback, 0) - 1, -1)
|
|
134
134
|
if isinstance(event := events[i], AssistantEvent)
|
|
135
|
-
if any(isinstance(b, ToolUseBlock) and b.name
|
|
135
|
+
if any(isinstance(b, ToolUseBlock) and matches_names(b.name, spec.edit_tools) for b in event.blocks)
|
|
136
136
|
),
|
|
137
137
|
None,
|
|
138
138
|
)
|
|
@@ -32,6 +32,14 @@ TOOL_ALIASES: dict[str, str] = {
|
|
|
32
32
|
|
|
33
33
|
TOOL_ALIASES_REVERSE: dict[str, str] = {v: k for k, v in TOOL_ALIASES.items()}
|
|
34
34
|
|
|
35
|
+
# cc-context routes real file edits through MCP tools whose bare names match no
|
|
36
|
+
# builtin edit gate; alias its write surface to the builtins those gates watch so
|
|
37
|
+
# an edit through the MCP can't slip past a Tool("Edit"/"Write"/"MultiEdit") guard.
|
|
38
|
+
MCP_TOOL_ALIASES: dict[str, str] = {
|
|
39
|
+
"ccx_code_edit": "Edit",
|
|
40
|
+
"ccx_code_replace": "Write",
|
|
41
|
+
}
|
|
42
|
+
|
|
35
43
|
READ_VERBS = frozenset({"get", "list", "search", "read", "view", "fetch", "query", "describe", "show", "find"})
|
|
36
44
|
|
|
37
45
|
|
|
@@ -482,28 +490,34 @@ def file_path_of(call: ToolCall) -> str | None:
|
|
|
482
490
|
|
|
483
491
|
|
|
484
492
|
def expand_tool_names(spec: str) -> frozenset[str]:
|
|
485
|
-
"""Expand a pipe-separated tool spec to include
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
)
|
|
493
|
+
"""Expand a pipe-separated tool spec to include alias and MCP bare spellings."""
|
|
494
|
+
base = set(spec.split("|"))
|
|
495
|
+
expanded = base | {alias for n in base for alias in (TOOL_ALIASES.get(n), TOOL_ALIASES_REVERSE.get(n)) if alias}
|
|
496
|
+
return frozenset(expanded | {bare for bare, builtin in MCP_TOOL_ALIASES.items() if builtin in expanded})
|
|
490
497
|
|
|
491
498
|
|
|
492
499
|
def matches_names(actual: str, names: Container[str]) -> bool:
|
|
493
500
|
"""Whether ``actual`` is one of ``names``, exactly or as an MCP tool suffix.
|
|
494
501
|
|
|
495
502
|
True when ``actual`` is in ``names``, or when it splits as
|
|
496
|
-
``mcp__<server>__<tool>`` on the first two ``__`` and ``<tool>``
|
|
497
|
-
|
|
498
|
-
|
|
503
|
+
``mcp__<server>__<tool>`` on the first two ``__`` and ``<tool>`` — or its
|
|
504
|
+
:data:`MCP_TOOL_ALIASES` builtin equivalent — is in ``names``. That alias
|
|
505
|
+
closes the edit-gate bypass where cc-context's ``ccx_code_edit`` /
|
|
506
|
+
``ccx_code_replace`` write through the MCP under names no ``Edit``/``Write``
|
|
507
|
+
gate would catch. Harness-rename aliases are not closed over — ``names`` is
|
|
508
|
+
taken verbatim; pre-expand with :func:`expand_tool_names` for those.
|
|
499
509
|
|
|
500
510
|
Example:
|
|
501
511
|
>>> matches_names("mcp__github__Grep", {"Grep"})
|
|
502
512
|
True
|
|
513
|
+
>>> matches_names("mcp__cc-context__ccx_code_edit", {"Edit"})
|
|
514
|
+
True
|
|
503
515
|
>>> matches_names("Execute", {"Bash"})
|
|
504
516
|
False
|
|
505
517
|
"""
|
|
506
|
-
return actual in names or (
|
|
518
|
+
return actual in names or (
|
|
519
|
+
(mp := mcp_parts(actual)) is not None and (mp[1] in names or MCP_TOOL_ALIASES.get(mp[1]) in names)
|
|
520
|
+
)
|
|
507
521
|
|
|
508
522
|
|
|
509
523
|
def tool_name_matches(actual: str, spec: str) -> bool:
|
|
@@ -473,7 +473,7 @@ impl Events {
|
|
|
473
473
|
let lo = index.saturating_sub(spec.reentry_lookback);
|
|
474
474
|
(lo..index)
|
|
475
475
|
.rev()
|
|
476
|
-
.find(|&i| self.entries[i].tool_uses().any(|tu|
|
|
476
|
+
.find(|&i| self.entries[i].tool_uses().any(|tu| matches_names(&tu.name, &spec.edit_tools)))
|
|
477
477
|
.map(|i| i as i64)
|
|
478
478
|
}
|
|
479
479
|
}
|
|
@@ -1316,6 +1316,10 @@ mod tests {
|
|
|
1316
1316
|
assert!(matches_names("mcp__conductor__ExitPlanMode", &names));
|
|
1317
1317
|
assert!(!matches_names("mcp__ExitPlanMode", &names));
|
|
1318
1318
|
assert!(!matches_names("AskUserQuestion", &names));
|
|
1319
|
+
|
|
1320
|
+
let edit_names: HashSet<String> = ["Edit".to_string(), "ccx_code_edit".to_string()].into();
|
|
1321
|
+
assert!(matches_names("mcp__cc-context__ccx_code_edit", &edit_names));
|
|
1322
|
+
assert!(!matches_names("mcp__cc-context__ccx_code_read", &edit_names));
|
|
1319
1323
|
}
|
|
1320
1324
|
|
|
1321
1325
|
#[test]
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|