Commit Graph
551 Commits
Author SHA1 Message Date
zeekay 61ca043a3d style: black --target-version py312 (unblock publish CI) forge/hanzo-tools-plan-v0.1.1 hanzo-tools-shell-v0.6.4 forge/hanzo-tools-fs-v0.3.2 forge/hanzo-tools-shell-v0.6.4 forge/hanzo-tools-vcs-v0.1.1 forge/hanzo-tools-code-v0.1.1 hanzo-tools-agent-v0.3.2 hanzo-mcp-v0.15.4 hanzo-tools-vcs-v0.1.1 forge/hanzo-mcp-v0.15.4 hanzo-tools-fs-v0.3.2 hanzo-tools-net-v0.1.1 hanzo-tools-plan-v0.1.1 forge/hanzo-tools-net-v0.1.1 hanzo-tools-code-v0.1.1 forge/hanzo-tools-agent-v0.3.2 2026-05-13 13:54:58 -07:00
zeekay 572dcd68f2 decomplect: HIP-0300 wire surface is the only public contract
The MCP wire (what tools/list reports) ships exactly one tool per axis:
fs, exec, code, git, fetch, plan — action-routed. The per-action classes
(ReadTool, WriteTool, EditTool, …) stay importable for in-process
read-only sandboxing (swarm sub-agents) but are NOT on the wire.

PyPI 0.3.1 of hanzo-tools-fs shipped the legacy split (7 tools) while
the local 0.3.1 source had already migrated to TOOLS=[FsTool]. Same
version number, two different contracts — the source of the
'Python MCP surfaces 32 tools, Node MCP surfaces 13' divergence
that breaks contract parity. Bumping to 0.3.2 publishes the
HIP-0300 surface for the first time.

- pkg/hanzo-tools-fs 0.3.1 → 0.3.2: TOOLS=[FsTool]; legacy classes
  importable; dropped 'Edit = EditTool' alias; cleaner __init__.
- pkg/hanzo-tools-shell 0.6.3 → 0.6.4: bump only (source already
  TOOLS=_get_detected_shell_tools()).
- pkg/hanzo-tools-code 0.1.0 → 0.1.1: bump only (TOOLS=[CodeTool]).
- pkg/hanzo-tools-vcs  0.1.0 → 0.1.1: bump only (TOOLS=[GitTool]).
- pkg/hanzo-tools-net  0.1.0 → 0.1.1: bump only (TOOLS=[FetchTool]).
- pkg/hanzo-tools-plan 0.1.0 → 0.1.1: bump only (TOOLS=[PlanTool]).
- pkg/hanzo-tools-agent 0.3.1 → 0.3.2: 'Edit' alias is gone — call
  EditTool by its real name in swarm_tool.py.
- pkg/hanzo-mcp 0.15.3 → 0.15.4: gets the HIP-0300-clean wire when
  consumed via 'uvx --refresh-package hanzo-tools-fs hanzo-mcp serve'.
2026-05-13 13:51:48 -07:00
zeekay c66e0302cd hanzo-memory: real BLAKE3 + fix render_vtt trailing newline
Two byte-equivalence bugs caught by cross-runtime parity check:

1. _blake3() was falling back to BLAKE2b when hashlib lacked BLAKE3 (it
   always does on stock CPython). Wallet addresses depend on the SAME
   hash across all five brain runtimes. Required the `blake3` pip
   package; no fallback. Python addresses now match the TS canonical
   (@noble/hashes/blake3): encode_address(32x0x00) → "hanzo:UFC8qCW8...".

2. render_vtt joined lines with "\n" and appended one "" at the end,
   producing a single trailing newline. Every other runtime emits "\n\n"
   after each segment so cues are separated by a blank line per WebVTT
   spec. Switched to explicit f-string append; render_srt fixed the same
   way.

53 tests still pass.
2026-05-11 12:27:11 -07:00
zeekay 794691d1d3 hanzo-memory: drop stale PARITY.md ref, export KNOWN_PROVIDERS
- Replace the dangling hanzoai/brain/PARITY.md pointer with an
  in-place cross-runtime note (Go brain + TS bot-memory).
- Add KNOWN_PROVIDERS to algorithms.__all__ so the inference
  provider whitelist participates in 'from algorithms import *'.

tests/test_algorithms.py --noconftest: 53 passed.
2026-05-11 12:11:44 -07:00
zeekay 9bf555d33e hanzo-memory: port fortemi algorithm parity to Python (53 tests)
Adds hanzo_memory.algorithms covering RRF/RSF, adaptive RRF, MMR, dedup,
Unicode script detection, FTS helpers (CJK bigrams, emoji trigrams,
websearch_to_tsquery, FTS5 MATCH), embed registry + MRL truncation,
UUIDv7 temporal bounds, WebVTT/SRT/RTTM captions, BPE token estimator,
MRR/recall/precision/NDCG eval, Haversine spatial, HTTP Range, wallet-
style address, graph maintenance (SNN/PFNET/Louvain), document-type
registry + auto-detect, circuit breaker + retry, provider slug + runtime
config, link-type rule classifier.

Run via pytest --noconftest tests/test_algorithms.py
See hanzoai/brain/PARITY.md for the cross-runtime contract.
2026-05-11 11:44:47 -07:00
zeekay 136a4e3ff1 brain: port graph-links + recipes to hanzo-memory (Python parity with bot/extensions)
Adds the zero-LLM typed-link extractor + YAML recipe loader to the
existing hanzo-memory Python SDK so a single brain.db file can be
written by the TS bot and read by the Python SDK and vice versa.

  graph_links.py — Edge dataclass, extract_edges(), reconcile(),
                   slugify(). Same six edge types
                   (mentions/attended/works_at/invested_in/founded/
                   advises), same regex + role inference, same code-
                   fence stripping. Pure — no I/O, no LLM.

  recipes.py     — list_recipes() + load_recipe(name). Reads built-in
                   recipes/ dir + optional HANZO_BRAIN_RECIPES path.

  recipes/email.yaml — flagship swipe-to-reply recipe, byte-identical
                       to the TS pack so cross-runtime brains agree.

  tests/test_graph_links.py — mirror of TS suite. 12 assertions cover
                              slugify, every edge type, code-fence
                              stripping, dedup, bare slugs, reconcile,
                              and recipe load.

hanzo-memory already had pluggable backends (SQLite + sqlite-vec via
.db.factory) and an MCP server; this fills in the gbrain-shape graph +
recipe surfaces so the Python SDK reaches feature parity with the bot
extensions in TS.
2026-05-10 18:39:39 -07:00
zeekay 49a07bb96e chore: remove dist-external/ after one-shot zap publish 2026-05-10 17:52:09 -07:00
zeekay 64e7e0a3a2 chore: add publish-external-dists workflow + zap-mdns/zap-protocol dists
Bootstraps hanzo-tools-browser v0.5.4 dependencies on PyPI.

- zap-mdns 0.1.0 (HIP-0069 mDNS publisher/discoverer)
- zap-protocol 0.2.1 (capnp wire protocol)
2026-05-10 17:49:04 -07:00
zeekay 2ecbd28aa5 style: black --target-version py312 (CI format-check fix)
No semantic changes — pure black reformat across the four files touched
in 55b55146 (hanzo-mcp 0.15.3 + hanzo-tools-browser 0.5.4).
forge/hanzo-mcp-v0.15.3 hanzo-mcp-v0.15.3 forge/hanzo-tools-browser-0.5.4 hanzo-tools-browser-0.5.4
2026-05-10 17:22:07 -07:00
zeekay c1da01a98b hanzo-mcp 0.15.3 + hanzo-tools-browser 0.5.4: ZAP TextContent normalization, mDNS-only discovery
hanzo-mcp (0.15.1 -> 0.15.3):
- _normalize_mcp_result() collapses FastMCP list[TextContent] to parsed JSON
  for ZAP MSG_RESPONSE serialization
- Closes the "TextContent not JSON serializable" bug surfaced when driving
  the Hanzo extension from agent via tools/call
- Bump hanzo-tools-browser[playwright] floor to 0.5.4

hanzo-tools-browser (0.5.2 -> 0.5.4):
- mDNS-only ZAP discovery via _hanzo._tcp.local. (HIP-0069); no port pool,
  no lockfile, OS-assigned ports advertised by hanzo-zap-mdns
- zap_server.py: refactor for unique server_id + retract on stop
- Test suite trimmed to the new wire contract

Patch-bump both packages.
2026-05-10 17:17:13 -07:00
zeekay a3bc5f5bcf fix(hanzo-tools-browser): 0.5.2 — import wire format from zap-protocol
The custom encode/decode and message-type constants in zap_server.py
were a byte-identical duplicate of zap-protocol (~/work/zap/zap-py).
Drop the duplicates, import from canonical:

  from zap.protocol import (
      ZAP_MAGIC, HEADER_SIZE, MAX_MESSAGE_SIZE,
      MSG_HANDSHAKE, MSG_HANDSHAKE_OK,
      MSG_REQUEST, MSG_RESPONSE,
      MSG_PING, MSG_PONG,
      ZAP_PORTS as DEFAULT_ZAP_PORTS,
      encode, decode,
  )

Single source of truth for the wire — any change (MSG_STREAM, frame
versioning, future Cap'n Proto migration) lands once and propagates.

zap-protocol added as a dependency. Verified at install:
  ZAP encode unified: True
  ZAP decode unified: True
2026-05-09 14:48:36 -07:00
zeekay 65cb749fa6 feat(zap-server): auto-publish via hanzo-zap-mdns + retract on stop
Every ZapServer.start() now publishes its bound port + agent_label as a
`_hanzo-zap._tcp.local.` mDNS record (best-effort — silently skipped
when `hanzo-zap-mdns` isn't installed). Browser extensions and any
LAN-wide agent can discover the server via `hanzo_zap_mdns.browse()`
without hard-coded ports or fragile lockfile registries.

Publish runs on a worker thread (asyncio.to_thread) so zeroconf's
internal multicast-socket setup doesn't block our event loop and
trigger EventLoopBlocked on zeroconf >= 0.140.

stop() retracts the announcement before closing the WS.
2026-05-08 12:10:26 -07:00
zeekay 41bdfa3644 fix(zap-server): race-free client cleanup when client_id is reused
When an extension reuses its client_id across consecutive ZAP connections
(probe followed by connectZap, both with mgr.state.extensionId), the
older websocket's finally clause was unconditionally popping the
client_id from _clients — deleting the new connection's freshly-installed
registration. The extension would then immediately disconnect because the
server-side state no longer had it, hammering reconnect loops.

Now the finally clause only removes the entry when it still points at
the closing websocket. Verified end-to-end: Firefox 1.9.x ZAP-native
connection holds steady; tabs/screenshot/evaluate round-trip in
11/73/5 ms.
2026-05-08 09:54:12 -07:00
zeekay 90e6e4f0d9 feat(tools-browser): ZAP-native 2-process architecture (0.5.0)
Each hanzo-mcp now hosts a ZAP server directly on the lowest free port
from [9999..9995], using a POSIX flock for cross-MCP arbitration. The
browser extension discovers and connects to this server without any
node-side bridge in the critical path.

- New hanzo_tools/browser/zap_server.py: wire format, server, lifecycle,
  client registry, leases, cluster-visibility config registry.
- _extension_command tries ZAP first (sub-1ms median round-trip on
  loopback), falls back to legacy HTTP bridge on :9224 only when no
  ZAP-connected client matches. Pinnable via BROWSER_TRANSPORT.
- New tool actions: list_mcp_instances, claim_browser, release_browser
  for sub-agent coordination across multiple parallel MCPs.
- Legacy CDP HTTP bridge no longer auto-starts (opt in with
  HANZO_CDP_BRIDGE_ENABLED=1). It remains available for non-ZAP MCP
  clients.

Tests: 30 new unit tests cover wire format, port arbitration,
multi-MCP coexistence, lease semantics, and cluster registry.
Bench shows 0.35ms median round-trip on local loopback.

Total tests: 4 baseline -> 35 passing (30 zap_server + 1 bench + 4 imports).
hanzo-tools-browser-0.5.0 forge/hanzo-tools-browser-0.5.0
2026-05-07 21:32:43 -07:00
zeekay 00b8c911ea feat(tools-browser): set_default_browser / use_browser actions for v1.9.0 bridge
The extension's bridge server (cdp-bridge-server.ts v1.9.0) added two
new actions for dynamic browser switching:

  set_default_browser — persist a default-target browser
  use_browser        — alias of set_default_browser

Both accept the browser name (firefox / chrome / safari / edge or a
specific instance ID like 'firefox-2') as the 'browser' field. The
bridge writes the choice to ~/.hanzo/extension/config.json so it
survives bridge restarts.

This commit:
- Adds the two action names to the Action Literal so the MCP tool
  accepts them.
- Adds them to extension_actions so they route through the bridge
  rather than falling to Playwright.
- The 'target_browser' parameter (already exposed) carries the
  browser name through to the bridge as 'browser', which is exactly
  what set_default_browser expects.

Bumps hanzo-tools-browser 0.4.5 → 0.4.6.
2026-05-07 21:07:22 -07:00
zeekay 9df3941de5 feat(tools-browser): add tab_id / client_id / target_browser params
Mirror the v1.8.3 extension bridge fix on the python side. The MCP
'browser' tool now exposes:

- tab_id — accepts the targetId returned by 'tabs' (e.g. "tab-1888868904")
  or a numeric tab id. Forwards as tabId so every action operates on the
  specified tab instead of the OS-active tab. Critical when the user has
  many windows open and the wrong one is in focus.
- client_id — pin to a specific connected extension instance (returned
  in 'status'). Use with 'list_browsers' to address one Chrome instance
  vs another Firefox instance bridged to the same hanzo bridge.
- target_browser — 'chrome' | 'firefox' per call. Per-call override of
  the global backend so a single MCP session can address Chrome and
  Firefox at different moments.

Also expose two action names that the bridge already supports:
  select_tab — bring a specific tab to focus (Target.activateTarget)
  list_browsers — enumerate every connected provider with details

The "tab-NNN" prefix from getTargets is automatically stripped and the
numeric id forwarded; the bridge's parseTabId() handles both formats.

Tested against extension v1.8.3 which lands the matching bridge changes.
2026-05-07 14:20:54 -07:00
zeekay 8ac68b91e3 chore: untrack node_modules, improve .gitignore 2026-04-18 17:15:22 -07:00
zeekay 69279a9151 fix: ruff lint auto-fixes across hanzo-mcp and tests 2026-04-01 20:48:58 -07:00
zeekay 83ec5c8807 fix: CTO review — version targets, slash command parity, dataclass default
1. pyproject.toml: ruff/mypy target py38→py312, remove 3.8-3.11 classifiers
2. command_suggestions.py: add /branch /commit /commit-push-pr /diff /stash /worktree
3. command_suggestions.py: fix aliases default None → Optional[List[str]]
2026-04-01 13:36:10 -07:00
zeekay ebb04882d6 feat: hanzo-dev Python TUI + LSP + hooks + sandbox + vim + git + multi-auth + full parity
Rename hanzo-repl → hanzo-dev to match @hanzo/dev (Rust/TS).

New packages:
- hanzo-lsp: async LSP client (diagnostics, go-to-def, references, context enrichment)
- hanzo-hooks: pre/post tool use hooks (shell scripts, exit-code deny)
- hanzo-sandbox: container detection, filesystem isolation, Linux unshare

hanzo-dev TUI:
- Vim keybindings (Normal/Insert/Visual/Command modes, 37 tests)
- Git slash commands (/branch /commit /worktree /diff /stash, 13 tests)
- All slash commands at parity: /model /permissions /clear /resume /memory
  /init /export /session /plan /solve /code /auto /fast /remote-control
- Multi-provider auth: Anthropic OAuth, OpenAI device code, Hanzo PKCE, auto-detect

Auth:
- login_with_anthropic() — PKCE via console.hanzo.ai
- login_with_openai() — device code flow via auth.openai.com
- login_auto() — env var detection + saved credential fallback
- OAuthCredentialStore supports provider keys (hanzo/anthropic/openai)

Parity test suite (38 tests): SSE, MCP normalization, permissions, compaction,
token usage, PKCE RFC vector, config, backoff, session roundtrip, hooks.

348 tests total, 0 failures across Python + Rust + Universe E2E.
2026-04-01 10:41:46 -07:00
zeekay ffe73447a3 security: fix 3 HIGH + 3 MEDIUM findings from red team review
- H-1: guard negative abs_off in obj_bytes() (buffer read bypass)
- H-2: remove CERT_NONE from ZapClient TLS (MITM protection)
- H-3: add MAX_MESSAGE_SIZE check in ZapServer (OOM DoS)
- M-5: log exceptions instead of bare pass in server
- L-1: validate ZAP version in Message.parse()
- L-2: wrap req_id at u32 boundary in CloudClient
forge/v2.4.0 v2.4.0
2026-03-31 20:57:16 -07:00
zeekay 985bec5352 feat: add CloudClient and rewrite wire protocol for Rust compatibility
- Add CloudClient for luxfi/zap binary protocol (TCP + auto-TLS)
- Rewrite wire.py Builder/ObjectBuilder to match Rust single-buffer architecture
- Fix response field offsets (CLOUD_RESP_BODY=4, CLOUD_RESP_ERROR=12)
- Use signed i32 relative offsets from absolute positions
- 28 unit tests + cross-language integration test passing
forge/v2.3.0 v2.3.0
2026-03-29 15:13:32 -07:00
zeekay 7e47625094 fix: lint — ruff format and fix for hanzo-tools-ui and hanzo-mcp 2026-03-27 20:00:21 -07:00
zeekay 7767986eea feat: add RAG search via Hanzo Cloud (search-docs + chat-docs)
Replace custom fastembed/sqlite-vec approach with Hanzo Cloud search
infrastructure. UI tool now has:
- ask: RAG chat about components via cloud-api.hanzo.ai/api/chat-docs
- semantic_search: hybrid fulltext+vector via cloud-api.hanzo.ai/api/search-docs
- rebuild_index: push components to Hanzo Cloud search index
- index_status: check search index stats

Uses publishable key (pk-hanzo-ui-search-2026) for reads, admin key for writes.
Same infrastructure as docs.hanzo.ai search.
2026-03-27 19:31:16 -07:00
zeekay fa7865c895 fix: registry client uses static JSON paths for CF Pages compatibility
Update RegistryClient to fetch from /api/registry/components.json and
/api/registry/components/{name}.json (pre-built static files), with
fallback to Next.js API routes. Works on CF Pages, GitHub Pages, and
server mode. Add lux registry URL (ui.lux.finance).
2026-03-27 19:15:46 -07:00
zeekay a07a57d6bb feat: add UI registry server and tiered backend (local → registry → github)
Add FastAPI registry server that pre-fetches all component data from
hanzoai/ui on GitHub, caches in memory, refreshes every 15min. Serves
instant cached responses. Deploy at ui.hanzo.ai.

- registry/cache.py: eager full-cache with concurrent GitHub fetching
- registry/server.py: FastAPI endpoints for components, blocks, search
- registry/client.py: RegistryClient matching GitHubAPIClient interface
- Dockerfile for containerized deployment
- UiTool now uses 3-tier fallback: local disk → registry → GitHub API
- Bump hanzo-tools-ui to 0.2.0, server deps optional (fastapi, uvicorn)
2026-03-27 19:06:38 -07:00
zeekay c0e7414b42 feat: enable ui tool in hanzo-mcp with local-first component reading
Add hanzo-tools-ui to workspace members and hanzo-mcp dependencies so
the ui tool is actually discoverable at runtime. Add LocalUIClient that
reads components directly from ~/work/hanzo/ui when available, falling
back to GitHub API. Adds list_packages and read_file actions. Fixes
GitHub config components_path to match actual repo layout (pkg/ui/primitives).
2026-03-27 18:50:09 -07:00
zeekay 244ff90dee fix: depend on hanzo-flow (hyphenated PyPI name) 2026-03-25 04:02:13 -07:00
zeekay 113d6f3e8b fix: flow CLI binary is 'flow' not 'hanzo-flow' 2026-03-25 04:01:09 -07:00
zeekay 931d9927fe fix: update hanzo-flow entry point to flow.launcher (internal rename) 2026-03-25 02:39:47 -07:00
zeekay 607cea5612 chore: cleanup — remove docker-compose.yml (use compose.yml), delete dead files 2026-03-25 01:52:18 -07:00
zeekay a820dd32de feat: add hanzo-flow package (re-exports hanzoflow CLI as hanzo-flow) 2026-03-25 01:23:47 -07:00
zeekay 3da9fecd20 chore: update SDK client, memory docs, and tests 2026-03-24 18:41:29 -07:00
zeekay 2c8c6a6f55 feat(memory): add namespace/key support + BlueRedChannel coordination class
- SQLite backend: namespace, key, tags, TTL, append support
- PluginMemoryService: full parity with TypeScript/Rust (list, stats, clear, tag, history, export/import)
- BlueRedChannel class for blue-red agent coordination protocol
- 30/30 tests passing
2026-03-24 18:03:30 -07:00
zeekay bd7e0078d9 chore: update hanzo-kms package 2026-03-23 10:26:07 -07:00
zeekay 959eab9db3 fix(api): add User-Agent header to APIs.guru fetch to fix CI 403
APIs.guru CDN blocks requests with Python's default User-Agent
(Python-urllib/3.x) from datacenter IPs, causing the weekly
Generate API Providers workflow to fail with HTTP 403.
2026-03-22 20:03:09 -07:00
zeekay 5ad26a7c78 chore: update dependencies to latest 2026-03-21 11:45:05 -07:00
zeekay 5480779e8a chore: update dependencies to latest 2026-03-21 11:01:05 -07:00
zeekay 7a5eba2dad feat(hanzo-tasks): Python SDK for durable task execution
New hanzo-tasks package wrapping temporalio SDK with Hanzo conventions:
- Client: connect, submit, get_result, cancel, signal, query
- Worker: register workflows/activities, poll and execute
- Pre-built workflows: AgentTaskWorkflow, PipelineWorkflow, FanOutWorkflow
- Pluggable agent executor via set_agent_executor()
- 28 tests passing
2026-03-19 10:29:31 -07:00
zeekay 867bda8090 rebrand: fix insights host URL and remove redundant env var fallback 2026-03-13 18:03:09 -07:00
zeekay 20778ab5c8 rebrand: PostHog→Insights in MCP analytics 2026-03-13 16:52:56 -07:00
zeekay df275b96f8 refactor(hanzo-mcp): clean up ZAP server bridge 2026-03-13 16:52:56 -07:00
zeekay 905cc907d8 test(zap,paas): add protocol and tool test suites
ZAP: 58 tests covering types, wire format encoding, server dispatch,
and full client-server integration over TCP (handshake, tool calls,
batch, ping, multiple clients, large payloads).

PaaS: 21 tests covering action routing, parameter validation, JWT
decode, auth fallbacks, deployment listing, and error propagation.
2026-03-13 16:52:56 -07:00
zeekay 46933ea6f5 fix(curl): accept json parameter in MCP tool registration
Field(alias="json") doesn't translate to Python kwargs — FastMCP
passes the schema name directly. Rename json_body to json in the
registered function signature.
2026-03-13 16:52:55 -07:00
zeekay 580ff05460 feat(hanzo-zap): add ZAP SDK package to monorepo (0.6.1)
Zero-copy Agent Protocol SDK — client, server, types.
Patch bump from PyPI 0.6.0 to bring into monorepo workspace.
2026-03-12 18:30:18 -07:00
zeekay e81722aeec ci: rename runners to {org}-{role}-{os}-{arch} convention
Unified ARC runner naming across all orgs:
- lux-build → lux-build-linux-amd64
- hanzo-build → hanzo-build-linux-amd64
- hanzo-k8s → hanzo-deploy-linux-amd64
- liquidity-build → liquidity-build-linux-amd64
2026-03-12 18:23:57 -07:00
zeekay c287c1eaf8 fix(zap): replace websockets with native ZAP TCP transport
- Rewrite zap_server.py to use asyncio TCP (not websockets library)
- ZAP server now speaks native binary protocol over raw TCP
- Wire format: [magic:4][type:1][length:4 BE][JSON payload]
- Remove websockets from ide optional dependency
- Fix type annotations: any -> Any, dict -> dict[str, Any]
- Add proper frame reading with asyncio.StreamReader.readexactly()
- Support MAX_MESSAGE_SIZE (16MB) limit per ZAP spec
2026-03-12 16:23:41 -07:00
zeekay 985bb9fedc chore(hanzo-mcp): bump version to 0.15.0
HIP-0300 bidirectional action sync release:
- Full action parity across Python/TS/Rust implementations
- 13 unified tools with complete action coverage
forge/hanzo-mcp-v0.15.0 hanzo-mcp-v0.15.0
2026-03-12 15:39:28 -07:00
zeekay 6548975fd9 fix: ruff format MCP files + update required tool count to 21 2026-03-12 01:40:46 -07:00
zeekay 997b7b91fb fix: resolve mypy errors and update shell tool count in tests
- Fix type shadowing in forgiving_edit.py (needle_lines int/list conflict)
- Add return type annotations to prompts functions
- Fix change_type indexing for None case in utils.py
- Fix commit.message bytes/str handling in utils.py
- Add proper dict typing for tree entries in utils.py
- Update shell tool count from 8 to 9 in test assertions
2026-03-12 01:30:57 -07:00