Commit Graph
161 Commits
Author SHA1 Message Date
retoor 1ebb7c637d docs: commit markdown previously hidden by the *.md ignore 2026-10-28 13:19:03 +01:00
retoor 4eff597be7 sessions: vault discovery tools, shared stdin, ctrl-key fixes
New sessions/session_export tools plus a sessions_block vault map in the system prompt (tai.py, ported to detz); recall/search carry a session footer instead of letting the model grep sealed bytes. write_file refuses new markdown at working/repo roots, and the blanket *.md gitignore is gone so docs stay visible. One LineInput owns fd 0 for every prompt (ask, approvals, shell_ask, secrets), ending phantom-empty answers; Ctrl-C re-prompts (double exits), Ctrl-D exits, Ctrl-Z suspends; mid-turn Ctrl-C announces itself and kills foreground shell children via RunInterrupted. Covered by SessionsTests, repl_keys.py pty checks, agent_diff sessions_block cases.
2026-10-28 13:11:45 +01:00
retoor e5a6e05ab5 whatsapp: merge wa-m1 wa-m2 wa-m3 2026-10-28 03:57:28 +01:00
retoor d79c184e2c whatsapp: M2 store 2026-10-28 03:42:07 +01:00
retoor 60c18bd4a1 whatsapp: M0 transpilation harness 2026-10-28 02:14:05 +01:00
retoor 12ee647d78 detz: baseline 1.46.1 pre-transpilation 2026-10-28 01:58:28 +01:00
retoorandClaude Sonnet 5.5 69542ab933 whatsapp: commit clear_device so --whatsapp-unlink really unlinks
clear_device deleted the device rows inside an implicit transaction and never committed,
so the delete was rolled back at process exit and --whatsapp-link answered "Already
linked". Test reopens the database and checks the device is gone and contacts are kept.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-27 21:40:52 +01:00
retoorandClaude Sonnet 5.5 bad5ea72ab whatsapp: one encrypted copy per device, treat an ack with error as a rejection
A message to the user's own number listed the phone twice (as recipient device and as
own device), so the server accepted it but nothing arrived. The device list is now
deduplicated; devices of the sender's user get the DeviceSentMessage wrapper, all
others the plain message (whatsmeow encryptMessageForDevices). The participant hash is
computed and compared with the server's (they match: 2:TKwG4B1n), and an ack carrying
error= is reported as a failed send instead of success.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-27 21:37:48 +01:00
retoor da67d8dad3 detz: release v1.45.0 WhatsApp link fix, image send, contact sync and search, failover hardening detz-v1.45.0 2026-10-27 21:32:38 +01:00
retoorandClaude Sonnet 5.5 1611f3baeb whatsapp: fix link/login 401, add image send, contact sync and search; harden failover
Root causes, each reproduced against the live server or endpoint:
- Server-only JIDs decoded as "@s.whatsapp.net" and pairing replies copied them
  into `to`, so the device was never registered and every login returned 401.
  Decoder/encoder fixed, replies use s.whatsapp.net, ADV hosted prefixes follow
  whatsmeow. The link wizard now waits for the restart, logs in, uploads prekeys
  and retries once with a fresh device on 401/403.
- Closed sockets made every receive loop spin until its deadline (the 7 minute
  CPU burn). Loops stop on a closed stream.
- whatsapp_send had no image argument and send_image was a stub. Added WaMedia
  (byte-exact against 8 wa-go golden vectors), media_conn upload, image send and
  the DeviceSentMessage copy for the user's other devices.
- Phone contacts never reached the client: added app-state sync (WaAppState,
  WaReceiver, LTHash and MAC checks verified against a whatsmeow-built oracle)
  and the historySyncConfig declaration at registration.
- Contact lookup: FTS5 trigram plus fuzzy ranking, ambiguity is reported and
  never guessed, global search lists contacts. Send caps (10/min, 200/day) are
  enforced and survive unlink.

Failover and agent:
- Every failed backend candidate is printed the moment it fails.
- muse runs with low reasoning effort, an empty preset and one stable workspace
  (36.5s down to 2.8s on the real prompt); Ctrl-C no longer counts as a backend
  failure; CLI backends use the circuit breaker; opencode runs are capped at 30s.
- Orphan tool results are dropped before sending (devplace HTTP 400, reproduced);
  compaction no longer starts its window on a tool result.
- Terminal art pasted as a prompt is refused before any model call.

Tests: whatsapp_test, muse_flags_test, llm_history_test; full suite 40 steps
(agent.e2e reads live tmux panes and is flaky, green on re-run).
Research archived under research/whatsapp-automation.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-27 21:32:38 +01:00
retoorandClaude Opus 4.8 bfc117b0c5 whatsapp: fix the real root cause of the pair-success crash (lifetime UB in serialize)
Replaying the captured failing frame proved the std::vector max_size() abort was
never a parser bug. It was an object-lifetime bug in WaDevice::serialize():

    put_blob(b, Bytes((jid ? *jid : "").begin(), (jid ? *jid : "").end()));

(jid ? *jid : "") builds a fresh temporary std::string for each evaluation, so
begin() and end() came from two different, already-destroyed objects; the range
constructor computed a garbage length and vector threw. It only misfired once
jid was set (after the phone scanned), which is why every parser test and the
initial unpaired save passed. Fixed by binding the value to a named const
std::string before taking iterators.

- src/whatsapp/wa_device.cpp: bind jid/lid before iterating; audited the tree
  for the same two-temporaries pattern (no other instances).
- tests/whatsapp_test.cpp: test_device round-trips a PAIRED device (jid+lid set,
  synthetic identifiers), the populated case that triggers the bug; runs under
  tools/san-whatsapp.sh.
- docs/whatsapp.md 13.7: records the real root cause and closes the open item.
- docs/cpp-safety.md: adds the object-lifetime rule (never take iterators from a
  temporary you rebuild) as a distinct bug class from size overflow.

Verified: replaying the captured pair-success frame now serializes, saves, and
encodes the response with no throw; build, whatsapp_test, make lint, and
tools/san-whatsapp.sh all green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-27 19:25:50 +01:00
retoorandClaude Opus 4.8 d34db8f215 cpp-safety: add the playbook doc and AGENTS rule (missed by *.md ignore)
docs/cpp-safety.md (the four-layer safe-C++ playbook and design decisions) and
the AGENTS.md standing rule were skipped by taicpp/.gitignore's *.md pattern in
79ae6f2; force-add them so the policy is actually in the tree, matching how the
other docs are tracked.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-27 19:04:11 +01:00
retoorandClaude Opus 4.8 79ae6f27da cpp-safety: safe-C++ playbook, fix a second UB, and a sanitizer net
Response to incident WA-2026-10-27 (the std::vector max_size() crash). Deep
research archived under research/safe-cpp-practices (8 Tier 1, 37 Tier 2, 2
conclusions) on production-safe C++ that keeps development speed: OpenSSF
compiler hardening, the C++ Core Guidelines bounds profile, integer-overflow
practice, libFuzzer/sanitizer CI, the sanitizer overhead ladder, clang-tidy
ratchets.

The research prescribed an ASan+UBSan+_GLIBCXX_ASSERTIONS build of the parsers.
Standing it up immediately caught a second, independent undefined-behavior bug
that two manual reviews had missed: a protobuf varint loop that shifted by up
to 70 bits (shift >= 64 is UB) on malformed input. Fixed and guarded by a
deterministic test and the sanitizer net.

- src/whatsapp/wa_proto.cpp: guard the wire-0 varint shift (the UB).
- tests/whatsapp_test.cpp: add an overlong-varint hostile case.
- tools/san-whatsapp.sh: the standing sanitizer net for detz::wa parsers.
- WaClient frame capture: a frame that fails to decode/dispatch has its exact
  bytes recorded to <home>/whatsapp/last-error.log (bounded), so the still
  unreproduced live <iq> failure becomes a one-paste deterministic fix. Wired
  from the wizard and the whatsapp_send tool.
- docs/cpp-safety.md: the project-wide playbook and design decisions (four
  layers: overflow-safe checked-reader parsing, cheap release hardening, the
  sanitizer test net, capture). docs/whatsapp.md section 13.6 records the
  follow-up and the honest open item. AGENTS.md makes it a standing rule;
  cap.md and mcp.md inherit it for their wire parsers.

Verified: build, whatsapp_test (incl. hostile+fuzz), make lint, and
tools/san-whatsapp.sh all green; research audit PASS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-27 19:03:32 +01:00
retoorandClaude Opus 4.8 713f08dc31 whatsapp: document the length_error crash and guard it with a hostile-input test
Record incident WA-2026-10-27 in docs/whatsapp.md section 13: the symptom (a
std::length_error core dump during --whatsapp-link after the QR refreshed), the
root cause (an overflowable `pos + len > size` bounds check plus an unguarded
dispatch loop), the fix (commit f16c5c6), and the standing rule for all code
that parses untrusted bytes: overflow-safe bounds checks, no unchecked
allocation from an attacker-controlled count, and no exception escaping a
top-level loop. The goal is C++ that a hostile peer can never crash.

Prevention is enforced, not just written: tests/whatsapp_test.cpp gains a
test_hostile section that feeds the parsers the exact shapes that crashed (a
4GB length field, an oversized protobuf varint, truncated frames, 2000 random
inputs) and fails if std::length_error is ever thrown again. Runs under
build/whatsapp_test / whatsapp.unit / make test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-27 18:36:14 +01:00
retoorandClaude Opus 4.8 f16c5c6ede whatsapp: fix crash on malformed node (length_error abort)
A protobuf/binary length field could be read as a huge value, and the
`pos + len > size` bounds check overflowed size_t and slipped past, so
vector::assign threw std::length_error. Node dispatch (pairing, etc.) was
not wrapped in a catch, so this aborted the whole process (core dump) during
--whatsapp-link after the QR refreshed.

- ProtoReader::next and the binary Decoder now use overflow-safe length
  checks (len > remaining) and the decoder reads 4-byte lengths unsigned and
  rejects anything larger than the frame; read_bytes rejects negatives.
- WaClient::dispatch wraps all node routing in try/catch: a bad node is
  logged and skipped instead of crashing the client.

Verified: build/whatsapp_test 16/16, make lint clean, and a live
--whatsapp-link run survives the QR-refresh window with no abort.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-27 18:32:49 +01:00
retoorandClaude Opus 4.8 115e403e67 whatsapp: native C++ client + terminal-screenshot tool
Native WhatsApp Web multi-device client in C++ (src/whatsapp/, namespace
detz::wa), built on OpenSSL plus a vendored public-domain ed25519 ref10
(third_party/ed25519, zlib) for XEdDSA and the nayuki QR generator
(third_party/qrcodegen, MIT); no new runtime dependency.

- WaCrypto, WaBinary, WaProto, WaNoise, WaSignal, WaDevice, WaSocket,
  WaClient, WaStore, WaQr, WaWizard.
- Verified offline against golden vectors captured from the real Baileys
  client (tests/whatsapp_data, from jfelipesjc/wa-go, MIT): HKDF/PBKDF2 RFC
  vectors, XEdDSA roundtrips, codec battery 19/19, ClientPayload byte-exact,
  the Noise handshake, and a 4-exchange Signal session byte-exact. Unit test
  build/whatsapp_test (16/16), run_all step whatsapp.unit.
- Verified live against web.whatsapp.com: `detz --whatsapp-link` connects,
  completes the Noise handshake, receives pair-device, renders a scannable QR
  in the terminal, and persists the device to the vault (whatsapp/<profile>.db).
  Also --whatsapp-status / --whatsapp-unlink.
- Agent tools whatsapp_send and whatsapp_contacts (detz-only, in DetzTools).
- Pairing completion after the phone scans, and the message send path
  (usync + prekey fetch + Signal encrypt + send node), are ported faithfully
  from whatsmeow but unverified in-tree (no linked account in development).
  send_image and own-device fan-out are not wired yet. See docs/whatsapp.md.

Also in this snapshot: the terminal-screenshot tool (src/termshot/,
terminal_screenshot, docs/termshot.md, research/terminal-screenshot-rendering)
and a concurrent session's in-progress llm/muse failover changes carried along
in the shared files.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-27 18:22:24 +01:00
retoorandClaude Opus 5.5 1a1448ddd0 docs: WhatsApp research and native C++ build spec
No native Python WhatsApp library exists (neonize is whatsmeow over
ctypes, yowsup is dead) and no browser is needed. Spec for detz::wa:
native C++ transpiled from wa-go (MIT, golden vectors) with whatsmeow as
referee, libcurl WebSocket plus OpenSSL, no new dependencies, build vs
deep-research table, caps, tests, phases, and a whatsapp-mcp shortcut.
Research archive: research/whatsapp-automation (70 sources, 3
conclusions). Nothing built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 16:55:18 +01:00
retoor 4875d40ac2 detz: release v1.44.3 Bump to 1.44.3 detz-v1.44.3 2026-10-25 19:25:54 +01:00
retoorandClaude Sonnet 5.5 4b43660e2b docs: cap agents and models, fuzzy matcher, orchestration, feed panes, README overview
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 19:16:18 +01:00
retoorandClaude Sonnet 5.5 ec9c471780 orchestration: sub agents render in live panels on the multiplexer screen
Feed panes in the multiplexer (vpane_* control commands, main-vertical layout, header row),
src/orch (board, panel, formatter, transport, CAP adapter), Agent observer and cancel flag,
supervision (idle warn/cancel, user close cancels, soft then hard stop), CAP answers collected
through the spill path. Research archived under background-work-limits.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 18:58:22 +01:00
retoorandClaude Sonnet 5.5 636886201b research: CAP model handling, model-as-tool and skill delegation (cap-protocol, +59 sources, 2 conclusions)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
chat-version
2026-10-25 18:24:40 +01:00
retoorandClaude Sonnet 5.5 0ac0584a96 fuzzy: generic FuzzyMatcher, fuzzy @agent/@model mention resolution, research archive
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 18:13:20 +01:00
retoorandClaude Sonnet 5.5 c5acc2249f cap: resolve @agent and @agent:model mentions via CapModelCatalog
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 18:01:34 +01:00
retoorandClaude Sonnet 5.5 94c973d782 glue: wire SealFactory into boot
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 07:26:15 +01:00
retoorandClaude Sonnet 5.5 20dc51e928 merge: worktree-agent-abfaf52b5a22064d5 (glue, main.cpp)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 07:24:24 +01:00
retoorandClaude Sonnet 5.5 e384fe5e46 merge: worktree-agent-ad389a7af758a1e42 (mplex final)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 07:24:18 +01:00
retoorandClaude Sonnet 5.5 fa85ae7fa5 skills: regenerate bundled_data.cpp from tai.py (deep-research text drifted)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 07:24:14 +01:00
retoorandClaude Sonnet 5.5 ad500b0327 glue: profile switch test, issues doc updated with the smoke results
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 07:23:43 +01:00
retoorandClaude Sonnet 5.5 0122771350 mplex: wiring doc notes
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 07:20:48 +01:00
retoorandClaude Sonnet 5.5 9f790e3177 glue: wire every port, flag dispatch and REPL host so build/detz runs the real agent
Adapters in src/glue for all ports of agent/ports.h (store, runtime, shell, ui, mcp, skills,
plexer, tui, ops, scheduler db), llm log sink and box, repl::ReplHost over agent::Agent, cap-speak,
serve-mcp, telegram and tui-local seams. main.cpp dispatches the flags in tai.py main() order.
Tests: tests/glue_persist.py (real model, restart persistence, one-shot shell call), tests/glue_flags.py,
tests/glue_ports.cpp. Spec: docs/glue.md, gaps: docs/glue-issues.md.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 07:20:01 +01:00
retoorandClaude Sonnet 5.5 f240cf5bf5 merge: worktree-agent-a4db72522a5ba2440 (makefile, test runner)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 07:13:14 +01:00
retoorandClaude Sonnet 5.5 e7f0227bcb taicpp: integrate build and tests (libdetz.a, per-module test binaries, tests/run_all.py, real lint, parity targets)
make test builds and runs 32 steps; not green: misc.diff and mplex.e2e fail on real module bugs.
test_main.cpp replaced by util_config_test.cpp; stale *.mk and store_test rule removed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 07:12:45 +01:00
retoorandClaude Sonnet 5.5 bdb81960c1 mplex: differential matrix (every command/flag/target and every default binding vs tai.py), runner script
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 07:10:33 +01:00
retoorandClaude Sonnet 5.5 9cc3415983 merge: worktree-agent-a34f619fc37ce62ae (cli argparse port)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 07:02:29 +01:00
retoorandClaude Sonnet 5.5 c8f6818997 cli: faithful argparse port (single flag table, HelpFormatter, textwrap, abbreviations, usage on error)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 07:02:03 +01:00
retoorandClaude Sonnet 5.5 ae0c62e705 merge: worktree-agent-a9d03b1708cbdcd2f (seal)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 06:57:09 +01:00
retoorandClaude Sonnet 5.5 c3440ffacd taicpp: port Seal subsystem (byte-compatible tai1$ envelope, rotation, boot upgrade factory)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 06:56:55 +01:00
retoorandClaude Sonnet 5.5 f44e505b0f integrate: resolve header collisions, keep both plexer-flow drivers in separate namespaces, rename shell pty to ptyproc, link -lz -pthread -lutil
Everything compiles; main.cpp still uses the removed placeholder agent API.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 06:48:34 +01:00
retoorandClaude Sonnet 5.5 2308e9e3df merge: worktree-agent-a3a407ad414d619b4
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 06:44:27 +01:00
retoorandClaude Sonnet 5.5 c1205649ba merge: ad389a7af758a1e42
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 06:44:27 +01:00
retoorandClaude Sonnet 5.5 a40556e0fd merge: worktree-agent-acc4f10dc5bae68cf
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 06:44:27 +01:00
retoorandClaude Sonnet 5.5 c04eee107c merge: worktree-agent-af1d14a13e54d3c51
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 06:44:27 +01:00
retoorandClaude Sonnet 5.5 fe9b49d2c0 merge: ae8675943507c4843
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 06:44:27 +01:00
retoorandClaude Sonnet 5.5 7a6d0ff326 merge: worktree-agent-a7652b893d520b1a0
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 06:44:20 +01:00
retoorandClaude Sonnet 5.5 96ca726c5b merge: worktree-agent-ad68a64045d79e2de (shell, util)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 06:44:20 +01:00
retoorandClaude Sonnet 5.5 2115023fcd merge: worktree-agent-a9b6872a3dc1e40d0
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 06:44:09 +01:00
retoorandClaude Sonnet 5.5 bbdc927215 tui: grr terminal client (Grr* classes), control socket, entry points, spec test, parity docs
Port of the grr client of tai.py: client, SSE stream, session, store, router, shell, views,
chat, panes, file viewer and the unix control socket; GrrTui::run is the --tui entry.
Verified against tai.py --tui on a real grr server over a pty: 236 steps, screen text and
per-cell styles identical except clocks, spinner frames and server-made ids.
docs/tui.md holds the symbol table and gaps, docs/wiring/tui.md the integrator hooks.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 06:15:05 +01:00
retoorandClaude Sonnet 5.5 9eaaada7a1 mplex: by-value args for set_active/select_pane/kill_*/discard_pane/add_buffer (member aliasing), regression test
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 05:14:26 +01:00
retoorandClaude Sonnet 5.5 24caef9ce4 taicpp: spec and wiring docs for the misc modules
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 05:06:43 +01:00
retoorandClaude Sonnet 5.5 1d962cd3f1 taicpp: port skills, scheduler, telegram, rag, install, release/audit backends with differential tests against tai.py
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 05:06:38 +01:00