Commit Graph

500 Commits

Author SHA1 Message Date
Peter Steinberger c23d66e3b5 refactor: consolidate coercion ownership (#122692)
* refactor: consolidate coercion ownership

* test: align shard check with weighted planning

* chore: refresh plugin SDK API baseline
2026-08-12 09:25:28 -07:00
Peter Steinberger 14b0011866 fix(imessage): preserve imsg retry-safe no-send result (#122672)
* fix(imessage): preserve retry-safe delivery failures

* test(imessage): avoid shadowing retry error

* test(imessage): assert approval account routing
2026-08-12 08:32:45 -07:00
Peter Steinberger b080dd1e76 refactor: consolidate coercion contracts (#122458)
* refactor: consolidate coercion contracts

Centralize exact string, record, numeric, date, Boolean, argument, and structured-error coercions while preserving call-site semantics.

Migrate canonical-name collisions and deprecated internal SDK bypasses, deleting 55 net production/tooling lines. Expand declaration ownership enforcement to 101 allowed helpers and add a narrow export-completeness audit.

* fix: preserve standalone script coercions

Keep copied Control UI tooling self-contained and retain the trusted release harness module-relative source seam when the harness runs against an old target cwd.
2026-08-11 23:26:37 -07:00
Peter Steinberger 964c8c84c1 refactor: consolidate coercion ownership (#122299)
* refactor: consolidate coercion ownership

Centralize four canonical coercion helpers, migrate exact core and plugin duplicates through narrow Plugin SDK facades, and enforce declaration and plugin-normalization ownership boundaries.

The sweep adds eight focused SDK exports while deleting more production and tooling code than it adds. User-visible behavior is unchanged except for safer equivalent object and UI parsing at existing boundaries.

* fix: guard integer option ownership

Register resolveIntegerOption with the canonical function owner and extend the declaration-guard fixture so future local duplicates fail validation.

* fix: keep integer helpers on numeric facade

Remove the unshipped duplicate string-coerce exports and route every affected plugin consumer through the existing number-runtime contract.

* fix: point numeric coercion to number runtime

Make boundary and declaration diagnostics recommend the canonical numeric facade, with failing-before coverage for both guidance paths.
2026-08-11 17:14:53 -07:00
Peter Steinberger fd1b965f2b refactor(plugins): remove orphan test API barrels (#121761)
* test(plugins): remove orphan test API barrels

* refactor(plugins): remove orphan test-only exports

* refactor(imessage): remove orphan test plugin

* test(plugins): remove stale package guard timeout
2026-08-10 16:42:34 -07:00
Ayaan Zaidi 9935ca3b30 fix(approvals): bind native requests to channel accounts (#121673)
Native approval delivery and resolution now stay bound to the originating or explicitly targeted channel account. Unbound requests fail closed across multiple eligible accounts; trusted reviewer-less SDK callers remain compatible.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-11 01:42:41 +05:30
Peter Steinberger 2904bbfc47 test(imessage): exercise chat lookup through runtime boundary (#121205) 2026-08-09 13:33:30 -07:00
Peter Steinberger 8616c0c374 refactor: finish shared test helper migrations (#120996)
* test: finish shared helper migrations

* test: fix helper migration CI

* style: fix test import ordering

* test(acpx): restore deferred void types

* test: fix helper migrations after rebase
2026-08-09 06:00:06 -07:00
Peter Steinberger c48339527a fix(imessage): deliver service-qualified media to existing chats [AI-assisted] (#115006)
* fix(imessage): resolve service-qualified media chats

* test(imessage): keep custody coverage on auto handles
2026-08-09 05:42:18 -07:00
Peter Steinberger 71a33f07a9 fix(imessage): make SSH-backed sends and actions reliable (#121038)
* fix(imessage): harden remote Mac transport

Route SSH-backed iMessage actions through JSON-RPC, preserve remote database paths, and stage outbound files on the Messages Mac with bounded cleanup. Keep local action semantics intact while failing closed on ambiguous wrappers and surfacing the remaining imsg v0.13.4 limits.

* fix(imessage): remove test-only exports
2026-08-09 04:48:38 -07:00
Peter Steinberger 54ae94530c refactor(approvals): simplify resolver plumbing (#120923) 2026-08-08 23:09:24 -07:00
Peter Steinberger e1ec95dcbf refactor(auth): dedupe profile upserts and approval resolvers (#120831)
* refactor(auth): dedupe profile upserts and approval resolvers

* test(auth): mock canonical locked upsert

* test(auth): mock locked upsert during onboarding
2026-08-08 21:14:16 -07:00
Peter Steinberger 75dbe52e3e refactor: one code path behind doctor legacy-state migrations (#120716)
* refactor(doctor): prefer manifest route-state owners

* refactor(doctor): unify config repair declarations

* refactor(doctor): unify legacy state migrations

* fix(doctor): satisfy migration pipeline guards

* fix(plugin-sdk): keep doctor adapter inside boundary
2026-08-08 18:23:15 -07:00
Peter Steinberger b55e1e3a55 fix(imessage): preserve native attachment message identities (#120739) 2026-08-08 16:21:18 -07:00
Josh Avant c691f2e41c fix(progress): preserve callback acceptance results (#120171)
* fix(progress): preserve callback acceptance results

* fix(progress): require transport acknowledgements

* fix(progress): preserve direct acceptance outcomes
2026-08-07 14:40:33 -05:00
Peter Steinberger c25671cf27 fix(imessage): stop dropping user text that collides with recent outbound sends (#120260)
* fix(imessage): text echo matching honors message-id conflicts; own sends stop feeding the loop limiter

Two silent-drop paths in the iMessage monitor:
1. The persisted 12h echo cache matched inbound user text against old
outbound text even when the GUIDs conflicted — a user sending 'ok' within
12h of the agent sending 'ok' was dropped as an echo. The text branch now
applies the same hasConflictingMessageIds guard the media branch has;
genuine reconnect echoes still match by id or id-less entries.
2. Every from-me row fed the echo loop rate limiter, so a normal outbound
burst (agent replies, multi-chunk sends, operator phone traffic) could trip
the limiter and silently suppress the next legitimate inbound message.
'from me' is no longer counted as a loop signal, and a tripped limiter now
logs a default-level warning once per conversation instead of verbose-only.

* fix(imessage): preserve delayed echo guards
2026-08-07 11:17:06 -07:00
Peter Steinberger f5e3b5ef54 refactor(plugins): single-source question reactions and preflight audio (#119987) 2026-08-06 14:47:36 -07:00
Peter Steinberger 7fd3363866 fix(imessage): deduplicate only configured watchers with canonical backend identity (#118974) 2026-08-03 14:37:27 -07:00
Peter Steinberger 6fa63a4e67 fix(imessage): honor explicitly enabled accounts during startup (#118944) 2026-08-03 13:58:42 -07:00
Peter Steinberger f9d9d1225a refactor(channels): own the lifecycle status contract in SDK patch factories (#118795)
* refactor(sdk): add channel lifecycle patch factories

* refactor(channels): adopt lifecycle patches in a-m

* refactor(channels): adopt lifecycle patches in n-z

* refactor(runtime): lifecycle-own ambient registries

* test(slack): assert lifecycle factory fields

* fix(sdk): preserve lifecycle patch extras types

* test(zalouser): widen lifecycle status sink

* test(irc): avoid shadowed status patch

* fix(zalo): reuse account-agnostic media route

* fix(gateway): accept explicit channel ready recovery

* test(qa): assert terminal Slack block fact

* test(qa): restore Slack blocked lifecycle scenario

* test(gateway): lock explicit lifecycle recovery contract
2026-08-03 12:39:48 -07:00
Peter Steinberger 4c66ed5615 feat(channels): lifecycle wave 2 — fifteen more channels publish recorded lifecycle (#118298)
* feat(channels): publish lifecycle from existing status sinks

* feat(channels): thread lifecycle through provider monitors

* fix(mattermost): keep lifecycle status helper private

* fix(matrix): preserve terminal lifecycle during startup cleanup

* fix(matrix): reject invalid tokens during startup

* test(mattermost): drop unused vi import
2026-08-02 17:30:56 -07:00
Peter Steinberger ff9955f01b refactor(imessage): consolidate approval test fixtures (#118306)
* test(imessage): consolidate approval fixtures

* test(imessage): avoid shadowing fixture factory

* test(imessage): preserve data-driven case titles
2026-08-02 17:10:56 -07:00
Peter Steinberger 2a635f21df refactor(imessage): consolidate status test fixtures (#118249) 2026-08-02 17:06:51 -07:00
Peter Steinberger f23a0c8fcf test(imessage): consolidate monitor fixtures (#118221) 2026-08-02 16:07:16 -07:00
Peter Steinberger f4bf253854 refactor(imessage): consolidate monitor route fixtures (#118108) 2026-08-02 11:34:50 -07:00
Yuval Dinodia 86c3486721 fix(imessage): rewind the recovery cursor when chat.db is replaced at the same path (#117788)
* fix(imessage): rewind the recovery cursor when chat.db is replaced at the same path

A restored, rebuilt, or symlink-retargeted chat.db keeps the configured
pathname, so it keeps the same recovery-cursor identity while its rowid
sequence restarts far below the persisted high-water. Startup then seeded
since_rowid with the stale value and imsg, which emits only rows above it,
suppressed every inbound message in the replacement database, including
messages arriving after the restart.

loadIMessageRecoveryCursor now takes the startup watermark and reconciles
the stored cursor against it. A cursor above the database's current
MAX(ROWID) cannot belong to the file now at that path, so the persisted
high-water rewinds to the new watermark and the monitor tails the
replacement database instead of skipping it.

* fix(imessage): rewind the recovery cursor for an empty rebuilt chat.db

A successful MAX(ROWID) on an empty message table yields null, the same value the watermark read returns for an unreadable database, so an empty rebuilt chat.db kept the stale high-water and suppressed its first rows. Return 0 for a readable empty table and keep null for an unavailable one.

* fix(imessage): preserve first row during empty database startup

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-08-02 17:00:01 +08:00
Peter Steinberger 8ae21a6ae5 refactor(approvals): share native channel factory routing (#117811)
* refactor(approvals): share native channel factory routing

* fix(approvals): pin routed factory target types

* refactor(approvals): isolate forwarding factory entrypoint

* refactor(plugin-sdk): rename flat approval params type; budget +1 for routed approval factory

* chore(plugin-sdk): regenerate API baseline for routed approval factory

* fix(channels): bind approval authorizer references for lint
2026-08-01 23:08:36 -07:00
Peter Steinberger d6e537a859 refactor(channels): share persistent state error reporting (#117813) 2026-08-01 22:06:25 -07:00
Peter Steinberger 4f707d15d8 fix(imessage): preserve trusted workspace attachment security (#117779) 2026-08-01 21:43:57 -07:00
Peter Steinberger ccee629359 refactor(plugins): delete registry compat scaffolding (#117749)
* refactor(plugins): delete registry compat scaffolding

* test(plugins): update CLI registry handle mock

* fix(plugins): preserve explicitly initialized hook registries

* test(plugins): update registry ownership fixtures

* fix(channels): restore registry snapshot memo
2026-08-01 21:18:47 -07:00
Peter Steinberger 6d5b25e24b refactor(imessage): deduplicate monitor route test fixtures (#117621) 2026-08-01 14:02:27 -07:00
Omar Shahine b67fa6a2c4 fix(imessage): prevent duplicate messages after delayed sends (#110853)
* fix(imessage): outlive imsg send fallback

* test(imessage): prove delayed fallback resolves once

* fix(imessage): preserve the send timeout floor

---------

Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>
2026-08-01 10:51:06 -07:00
Peter Steinberger ed5d046a58 fix(imessage): sanitize private context on every outbound path (#117501)
Co-authored-by: Peter Steinberger <steipete@macos.shared>
2026-08-01 09:40:02 -07:00
Harjoth Khara 41051fe37c fix(imessage): keep fenced role-marker mapping keys out of the outbound stripper (#117159)
* fix(imessage): stop the outbound sanitizer deleting fenced role keys

sanitizeOutboundText strips standalone `user:`/`system:`/`assistant:`
lines (leaked turn boundaries), `#+#` separators and `assistant to=`
markers, but the three regexes had no code-fence awareness. A bare YAML
mapping key like `user:` on its own line inside a ```yaml block matched
ROLE_TURN_MARKER_RE and was silently deleted before iMessage delivery,
reparenting its children under the wrong node — still-valid YAML, wrong
meaning, and nothing signalling a line was removed.

Skip matches whose offset falls inside a markdown code region for all
three patterns, reusing findCodeRegions/isInsideCode already applied by
the sibling reflection-guard on this channel. Regions are recomputed per
pass because each strip shifts later offsets. Leaked markers in prose are
still stripped.

Refs: #116942

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* test(imessage): cover code-aware marker stripping

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-08-01 16:52:47 +08:00
Peter Steinberger 338a7ccb2f fix(imessage): settle native inbound reply delivery (#117282)
Co-authored-by: Peter Steinberger <steipete@macos.shared>
2026-08-01 01:24:05 -07:00
Peter Steinberger ee320a6e41 fix(imessage): preserve outbound attachment delivery facts (#117238)
Co-authored-by: Peter Steinberger <steipete@macos.shared>
2026-07-31 23:36:48 -07:00
Peter Steinberger ba81a26db6 fix(imessage): preserve attachment filenames and bound recovery clocks (#117197)
Co-authored-by: Peter Steinberger <steipete@macos.shared>
2026-07-31 21:12:24 -07:00
Peter Steinberger 9e4381eb1c refactor(channels): unify bundled channel setup contracts (#117106)
* refactor(channels): canonicalize bundled setup contracts

* test(matrix): use scoped environment fixtures
2026-07-31 16:57:29 -07:00
Peter Steinberger 533807ab61 refactor: consolidate secure channel approval reaction bindings (#117105) 2026-07-31 16:51:25 -07:00
Peter Steinberger 36cc7bb105 fix(imessage): preserve voice intent and provider delivery failures (#116889)
* fix(imessage): honor configured attachment send transport

* fix(imessage): preserve send outcomes and voice delivery

* fix(imessage): preserve native voice transport contracts

---------

Co-authored-by: Peter Steinberger <steipete@macos.shared>
2026-07-31 08:03:37 -07:00
Omar Shahine 9bebf7ac43 fix(imessage): bold approval prompt labels in poll mode (#116221)
* fix(imessage): bold approval prompt labels in poll mode

#113193 added bold headers and labels to the approval reaction prompt, but
iMessage only shows that copy when tapbacks own the controls. On any
poll-capable bridge the details message is built from `manualFallbackPayload`,
the legacy unstyled builder, so every label (`Title:`, `Tool:`, `Host:`,
`CWD:`, `Full id:`, ...) reaches Messages as flat text. Native polls are the
default on a bridge-v2 host, so in practice #85954 still reproduced after it
was closed.

Add `nativeControlsPayload` to `ApprovalReactionPendingContent`: the same rich
copy as `reactionPayload` minus the tapback hint, for channels whose native
controls already own the decision surface. iMessage poll mode now renders it,
so both control paths deliver identical styled copy.

`imsg poll send --question` has no attributed-body channel, so the poll
question keeps the marker-free rendering of that same text; otherwise the
balloon would show literal asterisks.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Byq7UrC7ZpMHxoFXcddsa

* refactor(plugin-sdk): carry native-controls prompt copy as text

The iMessage poll path reads exactly one thing from the native-controls
payload: its text. Replace the ReplyPayload field with nativeControlsText so
buildApprovalReactionPendingContent stops running the metadata/session-key
builder for fields no caller reads, and the '?? ""' sentinel goes away.

Relative to main the SDK change stays additive: neither field exists in any
release; nativeControlsPayload only ever existed on this branch.

* refactor(plugin-sdk): expose native-controls prompt text as a builder, not a type field

ClawSweeper flagged that requiring a new member on the shipped
ApprovalReactionPendingContent type is source-incompatible for external
producers that hand-construct it. The hint-free copy does not need to ride
the type at all: export buildApprovalNativeControlsPromptText and let the
iMessage handler call it at payload-build time.

ApprovalReactionPendingContent is now byte-identical to the shipped shape;
the SDK change is a single additive function export. Signal/WhatsApp test
fixtures revert to their original form.

---------

Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 09:23:47 -07:00
Peter Steinberger 986e5d1758 refactor(channels): share ingress retention defaults (#115824) 2026-07-29 06:24:30 -04:00
Peter Steinberger bde6b166c0 refactor(channels): deduplicate ingress monitor shells (#115792)
* refactor(channels): deduplicate ingress monitor shells

* fix(channels): preserve ingress error overload types

* fix(channels): type ingress error overload implementation

* chore(plugin-sdk): ratchet ingress error surface
2026-07-29 05:33:00 -04:00
Peter Steinberger c402688894 feat(media): probe duration and dimensions for playback metadata (#115728)
* feat(media): probe playback metadata

* fix(media): satisfy CI gates

* fix(media): satisfy lint rules
2026-07-29 04:52:17 -04:00
Peter Steinberger 302f262e6b refactor: deduplicate extension normalization primitives (#115650)
* refactor(plugins): reuse SDK normalization primitives

* fix(ci): repair code-mode matrix checks

* fix(ci): satisfy code-mode matrix gates

* fix(ci): use matrix evidence export

* fix(ci): validate matrix evidence artifact
2026-07-29 04:10:06 -04:00
Peter Steinberger a24c1ceb3a fix(channels): release inbound debounce at admission (#115603)
Track full dispatch completion separately for error handling and shutdown drain while allowing same-session follow-ups to steer active runs. Fixes #113180.

Co-authored-by: Taksh <takshkothari09@gmail.com>
2026-07-29 01:38:15 -04:00
clawSean 8982d47a55 fix(imessage): apply canonical outbound sanitizer (#101430)
Co-authored-by: clawSean <260045960+clawSean@users.noreply.github.com>
2026-07-29 00:54:53 -04:00
Peter Steinberger 8e75df55d7 fix(imessage): explain unsupported private status probes (#115074) (#115526) 2026-07-28 23:55:53 -04:00
clawSean 4b32e6f0e8 fix(imessage): render complete poll selections [AI-assisted] (#114714)
* fix(imessage): render poll selection snapshots

* fix(imessage): scope empty poll selections to sender

---------

Co-authored-by: clawSean <260045960+clawSean@users.noreply.github.com>
Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
2026-07-28 03:28:08 -05:00
Peter Steinberger 0d7fb8eb39 refactor(fs): adopt fs-safe 0.5 core primitives (#113705)
* refactor(fs): unify exclusive file publication

* fix(fs): fence stale lock reclamation

* refactor(fs): bound wiki scans and secret reads

* chore(fs): finalize fs-safe 0.5 compatibility

* fix(fs): preserve publication ownership and legacy mode

* fix(fs): fail closed on unverifiable lock owners

* fix(fs): preserve concurrent backup publications

* refactor(fs): preserve ambiguous backup outputs

* fix(fs): preserve mixed-version lock coordination

* refactor(file-transfer): adopt fs-safe archive extraction

* refactor(fs): add bounded walk and secret seams

* refactor(auth): replace proper-lockfile with fs-safe

* fix(fs): honor Windows mode override casing

* refactor(snapshot): adopt fs-safe publication

* refactor(memory-wiki): adopt prunable root walks

* refactor(fleet): adopt bounded archive restore

* fix(fs): preserve post-publication ownership receipts

* refactor(fs): harvest final fs-safe primitives

* style(fs): clean harvest lint

* chore(plugin-sdk): refresh move helper API baseline

* refactor(snapshot): adopt native Windows ACL facts

* refactor(fs): adopt hardened atomic outputs

* fix(fs): scope lock reentrancy to logical owners

* chore(config): lower env var count budget

* fix(deps): adopt published fs-safe 0.5.0

* fix(ci): align SDK surface ratchets

* fix(ci): regenerate SDK API baseline after rebase

* fix(fs): preserve owner-scoped file lock nesting

* fix(ci): refresh SDK API baseline for file locks

* fix(fs): separate SQLite and file lock reentrancy

* fix(imessage): bound pinned attachment reads

* fix(agents): narrow session-key lock options

* fix(fs): preserve fs-safe 0.5 compatibility contracts

* fix(windows): retain private SQLite directory owner

* refactor(sqlite): centralize exclusive coordinator

* refactor(snapshot): isolate Windows ACL policy

* fix(windows): retain snapshot ACL inspector

* chore(config): realign env budget after rebase

* test(agents): accept canonical sandbox escape error

* docs(changelog): defer fs-safe release note
2026-07-28 03:41:47 -04:00