Commit Graph
168 Commits
Author SHA1 Message Date
retoor 88c3a6b2ea whatsapp: repair test brace junctions dropped by milestone merges 2026-10-28 13:34:19 +01:00
retoor de2a5209c9 whatsapp: merge M5 media (mediaconn, mediatype, stickers)
# Conflicts:
#	taicpp/CHANGELOG.md
#	taicpp/docs/whatsapp.md
#	taicpp/src/whatsapp/wa_client.h
#	taicpp/tests/whatsapp_test.cpp
#	taicpp/tools/wa-mapping.tsv
2026-10-28 13:29:38 +01:00
retoor b2c5f6047e whatsapp: merge M3 pairing (pairing, passkey, QR channel, wizard)
# Conflicts:
#	taicpp/CHANGELOG.md
#	taicpp/docs/whatsapp.md
#	taicpp/src/whatsapp/wa_client.cpp
#	taicpp/src/whatsapp/wa_client.h
#	taicpp/src/whatsapp/wa_consts.h
#	taicpp/src/whatsapp/wa_store.h
#	taicpp/tests/whatsapp_test.cpp
#	taicpp/tools/san-whatsapp.sh
#	taicpp/tools/wa-stub-scan.sh
2026-10-28 13:28:14 +01:00
retoor 87c8795ce7 whatsapp: merge M1 foundations (noise, socket, iq, cert, keepalive)
# Conflicts:
#	taicpp/docs/whatsapp.md
#	taicpp/src/whatsapp/wa_consts.h
#	taicpp/tests/whatsapp_test.cpp
#	taicpp/tools/san-whatsapp.sh
#	taicpp/tools/wa-stub-scan.sh
2026-10-28 13:26:03 +01:00
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 05d628d250 whatsapp: M5 media 2026-10-28 04:29:55 +01:00
retoor e5a6e05ab5 whatsapp: merge wa-m1 wa-m2 wa-m3 2026-10-28 03:57:28 +01:00
retoor 759acc7ab0 whatsapp: M3 pairing 2026-10-28 03:54:48 +01:00
retoor 499c6c5db6 whatsapp: M1 foundations 2026-10-28 03:42:33 +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