Skip to content

Commit efaec69

Browse files
CopilotbadMade
andauthored
merge: resolve conflicts with origin/main
Agent-Logs-Url: https://github.com/badMade/claw-code/sessions/442c1674-1472-45ea-b683-16bcc48794bc Co-authored-by: badMade <106821302+badMade@users.noreply.github.com>
1 parent ad838d9 commit efaec69

12 files changed

Lines changed: 327 additions & 47 deletions

.jules/bolt.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
## 2024-04-09 - Rust String Cloning Optimization
2+
**Learning:** In Rust, building lists of string parts for joining (e.g., `vec![string1.clone(), string2.clone()].join(" ")`) is a common pattern that can lead to unnecessary heap allocations. This codebase frequently does this when formatting reports. When the source values are already `String`s, borrowing them as `&str` and pushing them to a `Vec<&str>` before calling `.join()` entirely avoids these intermediate heap allocations. Additionally, calling `.to_string()` on static string slices just to appease a `Vec<String>` is wasteful when `Vec<&str>` works perfectly.
3+
**Action:** When constructing strings from parts using `Vec` and `.join()`, look for opportunities to use a `Vec<&str>` populated with borrowed string slices (`.as_str()`) instead of a `Vec<String>` populated with cloned strings (`.clone()`).
14

25
## 2024-05-18 - Caching Python Dataclass Properties for Routing Performance
36
**Learning:** In the Python port of the agent (`src/runtime.py`), the `PortRuntime._score` method processes routing modules on every input prompt. Repeatedly constructing a lowercase `haystacks` list in this hot loop causes redundant string allocations and `.lower()` calls, creating a measurable performance drag.
4-
**Action:** Use `@functools.cached_property` on the `PortingModule` (which is a `@dataclass(frozen=True)`) to lazily compute and cache a single search text string combining name, source hint, and responsibility, separated by `\0` null bytes to prevent overlapping field matches. Python 3.12+ supports `cached_property` on frozen dataclasses, allowing us to use this to avoid repeated string computations.
7+
**Action:** Use `@functools.cached_property` on the `PortingModule` (which is a `@dataclass(frozen=True)`) to lazily compute and cache a single search text string combining name, source hint, and responsibility, separated by `\0` null bytes to prevent overlapping field matches. This works here because `PortingModule` instances have a `__dict__` available for `cached_property` caching (that is, they are not slotted), allowing us to avoid repeated string computations.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"session_id": "03690d189e3a47a7988752f670bee42e",
3+
"messages": [
4+
"review MCP tool"
5+
],
6+
"input_tokens": 3,
7+
"output_tokens": 13
8+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"session_id": "50ed5c42f34b48e0b5d11332cc3bd467",
3+
"messages": [
4+
"review MCP tool",
5+
"review MCP tool"
6+
],
7+
"input_tokens": 6,
8+
"output_tokens": 32
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"session_id": "58914d03e535496e9da6b526139f7371",
3+
"messages": [
4+
"review MCP tool",
5+
"review MCP tool"
6+
],
7+
"input_tokens": 6,
8+
"output_tokens": 32
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"session_id": "af1faf843fab41fbbfad064544248ef5",
3+
"messages": [
4+
"review MCP tool",
5+
"review MCP tool"
6+
],
7+
"input_tokens": 6,
8+
"output_tokens": 32
9+
}

SECURITY.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Security Policy
2+
3+
## Supported Versions
4+
5+
Use this section to tell people about which versions of your project are
6+
currently being supported with security updates.
7+
8+
| Version | Supported |
9+
| ------- | ------------------ |
10+
| 5.1.x | :white_check_mark: |
11+
| 5.0.x | :x: |
12+
| 4.0.x | :white_check_mark: |
13+
| < 4.0 | :x: |
14+
15+
## Reporting a Vulnerability
16+
17+
Use this section to tell people how to report a vulnerability.
18+
19+
Tell them where to go, how often they can expect to get an update on a
20+
reported vulnerability, what to expect if the vulnerability is accepted or
21+
declined, etc.

patch_pr.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import sys
2+
3+
def replace_in_file(filepath, search_str, replace_str):
4+
with open(filepath, 'r') as f:
5+
content = f.read()
6+
7+
if search_str in content:
8+
content = content.replace(search_str, replace_str)
9+
with open(filepath, 'w') as f:
10+
f.write(content)
11+
print("Replacement successful.")
12+
else:
13+
print("Search string not found.")
14+
15+
search = """fn agent_detail(agent: &AgentSummary) -> String {
16+
let mut parts = vec![agent.name.as_str()];
17+
if let Some(description) = &agent.description {
18+
parts.push(description.as_str());
19+
}
20+
if let Some(model) = &agent.model {
21+
parts.push(model.as_str());
22+
}
23+
if let Some(reasoning) = &agent.reasoning_effort {
24+
parts.push(reasoning.as_str());
25+
}
26+
parts.join(" · ")
27+
}"""
28+
29+
replace = """fn agent_detail(agent: &AgentSummary) -> String {
30+
let parts: Vec<&str> = [
31+
Some(agent.name.as_str()),
32+
agent.description.as_deref(),
33+
agent.model.as_deref(),
34+
agent.reasoning_effort.as_deref(),
35+
]
36+
.into_iter()
37+
.flatten()
38+
.collect();
39+
parts.join(" · ")
40+
}"""
41+
42+
replace_in_file('rust/crates/commands/src/lib.rs', search, replace)

rust/crates/commands/src/lib.rs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3282,16 +3282,15 @@ fn render_agents_report_json(cwd: &Path, agents: &[AgentSummary]) -> Value {
32823282
}
32833283

32843284
fn agent_detail(agent: &AgentSummary) -> String {
3285-
let mut parts = vec![agent.name.clone()];
3286-
if let Some(description) = &agent.description {
3287-
parts.push(description.clone());
3288-
}
3289-
if let Some(model) = &agent.model {
3290-
parts.push(model.clone());
3291-
}
3292-
if let Some(reasoning) = &agent.reasoning_effort {
3293-
parts.push(reasoning.clone());
3294-
}
3285+
let parts: Vec<&str> = [
3286+
Some(agent.name.as_str()),
3287+
agent.description.as_deref(),
3288+
agent.model.as_deref(),
3289+
agent.reasoning_effort.as_deref(),
3290+
]
3291+
.into_iter()
3292+
.flatten()
3293+
.collect();
32953294
parts.join(" · ")
32963295
}
32973296

@@ -3325,13 +3324,14 @@ fn render_skills_report(skills: &[SkillSummary]) -> String {
33253324

33263325
lines.push(format!("{}:", scope.label()));
33273326
for skill in group {
3328-
let mut parts = vec![skill.name.clone()];
3329-
if let Some(description) = &skill.description {
3330-
parts.push(description.clone());
3331-
}
3332-
if let Some(detail) = skill.origin.detail_label() {
3333-
parts.push(detail.to_string());
3334-
}
3327+
let parts: Vec<&str> = [
3328+
Some(skill.name.as_str()),
3329+
skill.description.as_deref(),
3330+
skill.origin.detail_label(),
3331+
]
3332+
.into_iter()
3333+
.flatten()
3334+
.collect();
33353335
let detail = parts.join(" · ");
33363336
match skill.shadowed_by {
33373337
Some(winner) => lines.push(format!(" (shadowed by {}) {detail}", winner.label())),

src/commands.py

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
from __future__ import annotations
22

33
import json
4+
from collections.abc import Mapping
45
from dataclasses import dataclass
56
from functools import lru_cache
67
from pathlib import Path
8+
from types import MappingProxyType
79

810
from .models import PortingBacklog, PortingModule
911

10-
SNAPSHOT_PATH = Path(__file__).resolve().parent / 'reference_data' / 'commands_snapshot.json'
12+
SNAPSHOT_PATH = (
13+
Path(__file__).resolve().parent / "reference_data" / "commands_snapshot.json"
14+
)
1115

1216

1317
@dataclass(frozen=True)
@@ -24,10 +28,10 @@ def load_command_snapshot() -> tuple[PortingModule, ...]:
2428
raw_entries = json.loads(SNAPSHOT_PATH.read_text())
2529
return tuple(
2630
PortingModule(
27-
name=entry['name'],
28-
responsibility=entry['responsibility'],
29-
source_hint=entry['source_hint'],
30-
status='mirrored',
31+
name=entry["name"],
32+
responsibility=entry["responsibility"],
33+
source_hint=entry["source_hint"],
34+
status="mirrored",
3135
)
3236
for entry in raw_entries
3337
)
@@ -42,49 +46,78 @@ def built_in_command_names() -> frozenset[str]:
4246

4347

4448
def build_command_backlog() -> PortingBacklog:
45-
return PortingBacklog(title='Command surface', modules=list(PORTED_COMMANDS))
49+
return PortingBacklog(title="Command surface", modules=list(PORTED_COMMANDS))
4650

4751

4852
def command_names() -> list[str]:
4953
return [module.name for module in PORTED_COMMANDS]
5054

5155

52-
def get_command(name: str) -> PortingModule | None:
53-
needle = name.lower()
56+
@lru_cache(maxsize=1)
57+
def _get_command_lookup() -> Mapping[str, PortingModule]:
58+
lookup: dict[str, PortingModule] = {}
5459
for module in PORTED_COMMANDS:
55-
if module.name.lower() == needle:
56-
return module
57-
return None
60+
name_lower = module.name.lower()
61+
if name_lower not in lookup:
62+
lookup[name_lower] = module
63+
return MappingProxyType(lookup)
5864

5965

60-
def get_commands(cwd: str | None = None, include_plugin_commands: bool = True, include_skill_commands: bool = True) -> tuple[PortingModule, ...]:
66+
def get_command(name: str) -> PortingModule | None:
67+
return _get_command_lookup().get(name.lower())
68+
69+
70+
def get_commands(
71+
include_plugin_commands: bool = True,
72+
include_skill_commands: bool = True,
73+
) -> tuple[PortingModule, ...]:
6174
commands = list(PORTED_COMMANDS)
6275
if not include_plugin_commands:
63-
commands = [module for module in commands if 'plugin' not in module.source_hint.lower()]
76+
commands = [
77+
module for module in commands if "plugin" not in module.source_hint.lower()
78+
]
6479
if not include_skill_commands:
65-
commands = [module for module in commands if 'skills' not in module.source_hint.lower()]
80+
commands = [
81+
module for module in commands if "skills" not in module.source_hint.lower()
82+
]
6683
return tuple(commands)
6784

6885

6986
def find_commands(query: str, limit: int = 20) -> list[PortingModule]:
7087
needle = query.lower()
71-
matches = [module for module in PORTED_COMMANDS if needle in module.name.lower() or needle in module.source_hint.lower()]
88+
matches = [
89+
module
90+
for module in PORTED_COMMANDS
91+
if needle in module.name.lower() or needle in module.source_hint.lower()
92+
]
7293
return matches[:limit]
7394

7495

75-
def execute_command(name: str, prompt: str = '') -> CommandExecution:
96+
def execute_command(name: str, prompt: str = "") -> CommandExecution:
7697
module = get_command(name)
7798
if module is None:
78-
return CommandExecution(name=name, source_hint='', prompt=prompt, handled=False, message=f'Unknown mirrored command: {name}')
99+
return CommandExecution(
100+
name=name,
101+
source_hint="",
102+
prompt=prompt,
103+
handled=False,
104+
message=f"Unknown mirrored command: {name}",
105+
)
79106
action = f"Mirrored command '{module.name}' from {module.source_hint} would handle prompt {prompt!r}."
80-
return CommandExecution(name=module.name, source_hint=module.source_hint, prompt=prompt, handled=True, message=action)
107+
return CommandExecution(
108+
name=module.name,
109+
source_hint=module.source_hint,
110+
prompt=prompt,
111+
handled=True,
112+
message=action,
113+
)
81114

82115

83116
def render_command_index(limit: int = 20, query: str | None = None) -> str:
84117
modules = find_commands(query, limit) if query else list(PORTED_COMMANDS[:limit])
85-
lines = [f'Command entries: {len(PORTED_COMMANDS)}', '']
118+
lines = [f"Command entries: {len(PORTED_COMMANDS)}", ""]
86119
if query:
87-
lines.append(f'Filtered by: {query}')
88-
lines.append('')
89-
lines.extend(f'- {module.name}{module.source_hint}' for module in modules)
90-
return '\n'.join(lines)
120+
lines.append(f"Filtered by: {query}")
121+
lines.append("")
122+
lines.extend(f"- {module.name}{module.source_hint}" for module in modules)
123+
return "\n".join(lines)

src/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22

3-
from dataclasses import dataclass, field
43
import functools
4+
from dataclasses import dataclass, field
55

66
@dataclass(frozen=True)
77
class Subsystem:

0 commit comments

Comments
 (0)