* feat(native): search analyzed memory for masked byte patterns
The diff adds search_bytes to the CLI, the shared MCP contract, Ghidra
inventory, and the headless bridge, and advertises the same operation on
Hopper as unavailable until that provider is verified. Patterns are
hexadecimal byte pairs with optional ?? wildcards and an optional
equal-length bit mask; the TypeScript boundary and the bridge both
require a nonempty pattern, equal lengths, and at least one constrained
bit. Ghidra walks initialized blocks in address order within inclusive
bounds, keeps overlapping matches inside a single block, and returns
each hit with its segment, unique source file offset, and containing
procedure, continuing through a cursor bound to the target, profile,
pattern, mask, and bounds. Each page reports the inclusive ranges
examined and the skipped uninitialized blocks; cancellation returns a
typed error and discards the active Ghidra database.
address_to_file_offset now uses the same unique-offset helper, which
rejects a mapping that is missing, ambiguous, or larger than a safe
integer.
* fix(native): limit unbounded byte search to loaded memory
Without start or end, search_bytes walked every Ghidra block, including
non-loaded file parts such as .symtab and overlay blocks, which the docs
call out of scope. Unbounded searches now skip those blocks and list them
in searched.skipped_not_loaded; explicit bounds in their address space
still search them. Document that a match must end at or before end.
* fix(native): preserve implicit address spaces in range consumers
* fix(native): reject present malformed byte search state
---------
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* feat(setup): add Kimi Code client support
Registers rea in ~/.kimi-code/mcp.json (or $KIMI_CODE_HOME/mcp.json), preserving unrelated settings with a .rea.backup; registration is command-based stdio with no type field, startupTimeoutMs 30000 and toolTimeoutMs 120000 from MCP_STARTUP_POLICY.
Strict JSON parsing: empty or whitespace-only files initialize; malformed JSON is rejected untouched with no backup; explicit transport other than stdio reports invalid.
Bundled skill uses the shared ~/.agents/skills destination that Kimi Code discovers, installed and verified through the shared-skill flow.
Validated by 19 Kimi-specific tests, 260 adjacent-client regressions passing, check:fast and docs:check, and real-client verification on Kimi Code 0.40.1 (173 tools discovered, real mcp__rea__analyze_javascript_application call succeeded).
* fix(setup): preserve Kimi tool filters and strict JSON coverage
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(host): separate REA host support from Hopper installer targets
LinuxDistribution.supported carried two meanings at once: that the host runs
REA, and that the automated Hopper installer is tested on it. The doctor read
the first meaning from the second, so Debian-derived hosts such as Kali
reported unsupported_host while their providers worked normally.
Rename the field to hopperSetupSupported, which only the Hopper installer and
setup planning consume, and derive host support from the package family
through supportsReaHost(). Any distribution with a recognized apt, dnf, or
pacman family is now a REA host. The tested Hopper installer list is
unchanged, so Debian and Kali keep falling back to configuring an existing
provider instead of downloading an untested package.
Verified on Kali 2026.3 (Debian testing, x86_64): rea doctor reports a healthy
environment with Ghidra 12.1.4, and analyze_function decompiles an x86_64 ELF
through the MCP server. npm run check, npm run docs:check, and the application
and Ghidra suites pass. No Hopper or IDA host workflow was exercised.
* fix(setup): stop skill checks after first drift
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(cli): label each uninstall skill root by its client
rea uninstall reported every managed skill destination under the
shared "skill" label (with only Claude Code special-cased), so a
retained or failed directory could not be told apart from the others.
Use the destination's client identifier so the aggregated detail names
each root: "shared: retained (...)", "claude_code: removed (...)",
"antigravity: retained (...)". Retained and failed entries now point to
the specific directory that needs attention.
Fixes#2111
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(cli): align skill summary assertions with client and path labels
---------
Co-authored-by: wjl8636 <wjl8636@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(comparison): preserve incomplete function call evidence
Keep missing, unknown, partial and unresolved call relationships unknown in function comparisons and reconstruction claims. Aggregate IDA caller and callee coverage without overwriting uncertainty.
Validate with 144 focused tests, typecheck/lint, docs checks and test discovery. Real providers were not verified; the full headless IDA session suite requires unavailable Windows native controls.
* fix(comparison): recheck historical calls-only changes
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Error results reach the wire as text plus `isError: true`, but the
text-only envelope omitted the flag. An error up to 15 bytes above the
result budget passed both the delivery and transport checks and was sent
as the original diagnostic instead of taking the oversized-error recovery
path.
Rename the error representation to "error-text" and size its envelope
with the flag, so ToolResultDelivery and the error transport share the
complete delivered shape. Successful structured results are unchanged.
Fixes#2557
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(sqlite): keep triggers whose declaration spells the table in another case
SQLite stores a trigger's target in sqlite_schema.tbl_name exactly as
written in CREATE TRIGGER and resolves it by ASCII case folding, while an
index stores the table's own name. The selected_table scope filtered
tbl_name with COLLATE BINARY, so a trigger declared ON users for table
Users was omitted while the schema still reported complete. Match
dependents with COLLATE NOCASE, and report each trigger's table as the
stored table or view name so the selected-table contract still holds.
* fix(sqlite): refuse an inexact table before the case-folded schema scan
With the NOCASE expansion, a selection such as users for table Users
expanded the stored table's declarations before readRows reported the
missing exact name, so large trigger definitions could surface as an
output-limit failure instead of the selection error. Check the exact
table name against PRAGMA table_list first and share the selection
failure with readRows.
* fix(sqlite): fold dependent names only for a row-selectable table
An exact view, virtual or possible shadow table passed the exact-name
guard, so the NOCASE scan could still expand a differently cased trigger
past the reply budget before readRows refused the selection. Fold case
only when the selection is an ordinary table that is not a possible
shadow table, and keep the exact filter otherwise so every refused
selection fails as it did before the case-folding change.
* fix(sqlite): resolve trigger tables without folding unrelated names
The stored-name lookup case-folded every PRAGMA table_list name up front,
so a selected-table inspection of a tiny table paid for large unrelated
identifiers. A selected-table scan only returns the selected table's
dependents, so report the selected name directly; other scopes use an
exact stored name when one matches and fold the stored names once, only
when a trigger spells its target differently.
* perf(sqlite): fold each table name once when matching shadow parents
The extracted shadow-parent helper folded the table name inside the find
callback, once per unresolved virtual table, and the selected table was
checked both before and during the schema scan. Fold the name once per
call as before, and reuse the selected table's result in the scan.
* Single owner for the Chrome DevToolsActivePort startup deadline
Cold Chrome startup tolerance was spelled three ways for one wait: the helper
fell back to 15,000 ms, the runtime fixture lifecycle passed a literal 60,000,
and the real-browser verifier kept a local 60,000 constant. A per-caller literal
quietly changes how long a lane tolerates a cold browser before it fails, and
the failure reported only elapsed_ms, so a reader could not see which ceiling
was hit.
Export BROWSER_DEVTOOLS_STARTUP_TIMEOUT_MS as the owner, use it for the helper
fallback and both call sites, and report startup_timeout_ms in
BrowserStartupError. A source guard keeps callers from restating the number.
* Pin the DevToolsActivePort deadline guard to the startup call argument
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Split two over-long test functions into module-level helpers
(max-lines-per-function): IdaSessionClient transport cases, IDA provider
composition, and function comparison identity cases keep their names and
assertions.
Also fix three typecheck errors: default omitted
direct_invokes_exhaustive to null so the result schema stays JsonValue
compatible, parse the ghidra dossier before spreading it, and delete the
optional beforeCall hook instead of assigning undefined under
exactOptionalPropertyTypes.
* fix(ida): let one-shot commands exit after retaining cleanup
When a headless IDA request outlives timeoutMs (for example idb_open on
a large binary still running auto-analysis), REA cannot prove the
worker stopped and correctly retains the upstream connection and
private workspace. The retained stdio child and its pipes stayed
referenced, so a one-shot CLI printed its cleanup_incomplete result and
then never exited, keeping the supervisor, worker and database alive.
Detach the retained connection's child process and pipes from the event
loop when cleanup fails. A long-lived MCP server can still retry
through the retained connection; a one-shot CLI exits with status 1,
and the supervisor observes end of input.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ida): report an unverified upstream worker after failed cleanup
Upstream ida-pro-mcp spawns headless workers in their own session and
deliberately leaves them running when its supervisor exits, so neither
a retained connection nor REA exiting proves that a timed-out worker
stopped. When cleanup fails before the owned worker's release is
confirmed, the cleanup diagnostics now name its private session and
state that it may still be running until it finishes and reaches its
idle timeout. Failures after a confirmed release, or before any open
was attempted, do not report a worker.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ida): name the inventory sessions that block worker release
When idb_close confirmed the requested worker gone but the follow-up
inventory still found a different peer on the private input, the
upstream_worker diagnostic named the released session and could
misdirect manual cleanup. Record the session ids of the inventory
entries that actually blocked release and report those; fall back to
the requested private session only when no inventory evidence exists
(an incomplete open or an unanswered request). The field becomes
session_ids, since more than one entry can block release.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ida): keep blocker evidence and backend in cleanup diagnostics
The release diagnostic reset its observed blockers on every close, so a
retry whose inventory was unavailable fell back to the already-released
session; and it kept only session ids, describing a blocking GUI
session with detached-worker guidance.
Blocker evidence is now replaced only by a successful inventory, and
the diagnostic becomes upstream_sessions with each session's id and
backend, with guidance that distinguishes workers from GUI sessions.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ida): stop naming a worker after its close was confirmed
When idb_close confirmed the requested worker's release but the
following inventory failed, no blocker evidence existed yet and the
diagnostic fell back to the confirmed-absent worker. After a confirmed
close the diagnostic now reports an empty session list, meaning any
remaining same-input sessions are unknown.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(ida): group cleanup diagnostic cases in their own suite
The added cases pushed the reaped-worker describe block past the
150-line limit enforced by lint:built.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ida): keep ownership and pre-close peers in cleanup diagnostics
Blocking sessions dropped the parsed ownership fact, so an external
unowned worker looked the same as REA's own; and recovery inventory
recorded same-input peers only when the requested worker was missing,
so a peer seen beside it was lost if the following close failed.
Each reported session now carries owned (null when no inventory has
reported it), and recovery records every same-input session until a
later successful inventory replaces that evidence.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ida): drop a confirmed worker from retained cleanup blockers
Recovery inventory now records the requested worker beside any peers,
so once idb_close confirmed its release a failing follow-up inventory
still reported it as unreleased. Remove the confirmed session from the
retained blockers at close confirmation and keep the remaining peers.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(ida): retry cleanup through a detached stdio connection
The retry coverage used a recording connection whose detach() only
counts calls, so it could not show that detaching keeps a retained
connection usable. Run a real stdio supervisor in a long-lived host,
fail the first post-close inventory, and require the retry through the
same detached connection to confirm release and remove the workspace.
The test fails if detach() destroys the pipes instead of unref-ing them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ida): close the stdio supervisor in failed retry tests
Merge main and give its new IdaNativeProtocol connection double the
required detach() method. The real-stdio retry test now closes its
connection in an unconditional teardown, so a failing assertion cannot
leave the supervisor waiting on stdin.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(ida): share the cleanup diagnostic expectation in session tests
Repeated upstream_sessions assertions and the unrelated live peer
literal pushed repository duplication over the jscpd threshold. Build
the expected diagnostic with one helper and reuse one peer constant.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(ida): distinguish observed ownership from unreported input bindings
* fix(ida): keep requested-ID conflicts in recovery cleanup
Recovery inventory kept only same-input entries, unlike the startup and
post-close filters. After an explicitly rejected open, an entry under
the requested session ID on another input was dropped, so cleanup could
close the connection, remove the private workspace and report success
while that session stayed registered. Match the requested ID as well so
the entry is retained as a blocker and cleanup stays incomplete.
Also split the cleanup diagnostics suite under the lint:built function
length limit, and make two startup-inventory fixtures pass a defined
session id so the test file typechecks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ida): preserve retained session inventory facts
---------
Co-authored-by: Xingchuan Ma <xingchuan.ma@msn.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
Move all 18 translated READMEs into docs/readme/ and keep the English entry at the repository root. Update navigation, guide/image paths, website discovery and documentation checks together.
Preserve the contributor's work and current main content. Cover every translated command and HTML destination, and repair the verified Persian heading fragments.
Validation: 203 focused tests on the synchronized head, plus 119 tests and documentation checks on the integration with main fc0dbe7f9; 1,501 local references and 399 authored fragments verified. The complete CI workflow passes. The upstream x64 dylib fixture correction is included; an unchanged-checkout rerun cleared the earlier deadline timing assertion.
Closes#2141
Co-authored-by: Aimal Khan <94559553+aimalexe@users.noreply.github.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
* docs(skills): add CI and test correctness auditing
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
* fix(process): report no remaining time after a provider deadline fires
Node timers can fire while performance.now() is still a fraction of a
millisecond short of the monotonic deadline. ProviderStartupDeadline then
reported interruption "timeout" and an aborted signal while remainingMs()
returned ceil(0.x) = 1, so polling loops guarded by remainingMs() > 0
(Hopper and Ghidra startup) could run past an elapsed deadline, and the
real-timer test "aborts a bounded wait when its real monotonic deadline
expires" failed intermittently in CI (expected 1 to be 0).
Once the deadline's own timer has classified a timeout, report zero
remaining time. A deterministic regression test fires the timer with the
monotonic clock 0.4 ms short of the deadline.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(process): retain the monotonic startup deadline budget
Recheck the absolute monotonic deadline when an early timer fires, and keep
polling waits pending until their own target or the shared deadline arrives.
Preserve caller cancellation, disposal and the unchanged real-timer assertion.
This replaces the earlier remainingMs workaround: an early callback must not
classify an unexpired deadline as a timeout.
Adapt the production fix and regression cases from nosmile99 PR #2793 at
546001693636f13700d86c6e93b6086abba2b7d6, including the independently reported
both-timers-early reproduction. Preserve the prior contributor's commit.
Fixes#2760
Co-authored-by: nosmile99 <147114285+nosmile99@users.noreply.github.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
* style(tests): format the Java class fixture signature
The captured main baseline has an unformatted helper signature. Apply the
repository formatter so the required style gate can run to completion.
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
* test(ghidra): group expanded suites by their contracts
Split result-envelope and completeness checks, and Windows invocation and
runtime checks, into named describe groups within the existing lint limit.
Preserve every test, fixture, assertion and platform prerequisite.
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
---------
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: nosmile99 <147114285+nosmile99@users.noreply.github.com>
* fix(ida): retain bounded stderr on upstream transport failures
* fix(ida): preserve stderr through operation and cleanup boundaries
Address review findings at their producing boundaries and preserve directly affected consumers. Source inspection and git diff --check completed. Tests and automated checks were not run at the user’s explicit request.
* fix(ida): preserve cancellation and single-owner stderr diagnostics
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(flutter): reject ambiguous mappings and bound ELF notes
Resolve PT_LOAD interpretations once for symbols and dynamic tables, including partial overlaps. Preserve equivalent mappings and leave conflicting or invalid alternate definitions unresolved.
Bound distinct nonempty ELF note ranges before retention and reads, deduplicate shared ranges, preserve observed build-ID candidates and report partial coverage on exhaustion. Correct shared verifier workspace ownership and structured Windows path assertions.
Addresses the two post-merge review findings on PR #1582. Validation: 147 focused cases across Linux, macOS Sonoma 14.8.9 and non-administrator Windows 11 build 26300.9457; real Gallery CLI/MCP checks on all three hosts; six compiler-produced ELF32/ELF64 hash-layout cases; static, docs, discovery and duplication checks. Full string-pool projections remain explicitly bounded.
* test(flutter): parse complete facts through named result schemas
---------
Co-authored-by: me <me@medz.org>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(setup): resolve the configuration MSIX Claude Desktop reads
On Windows, setup, doctor and uninstall always used
%APPDATA%\Claude\claude_desktop_config.json. The MSIX build of Claude
Desktop (package family Claude_pzs8sxrjxfjjc) virtualizes AppData writes
and reads its package-private copy under
%LOCALAPPDATA%\Packages\<family>\LocalCache\Roaming\Claude once it exists.
Setup from an ordinary process therefore wrote a file the app never reads,
and doctor reported that file healthy.
Resolve the Claude Desktop location once, in supportedClients(): the
private copy when it exists, else the AppData file the package still
reads, else a new private copy. An unrecognized Claude_* publisher or
unreadable package storage is reported instead of falling back to AppData.
Compare one of the package's private files with its AppData path through
realpath.native to learn whether the running package started this
process. From that redirected view, or when no file can be compared,
setup and uninstall refuse to change Claude Desktop's configuration,
because the running app rewrites it from memory. From a redirected view
they also refuse writes under %APPDATA% and %LOCALAPPDATA% for other
clients and skills, which would land in the package's private storage.
Setup refuses to register a launcher stored in any MSIX package's
private storage, discloses which file the package reads, and tells the
user to quit Claude Desktop fully on every platform. Configuration fails
with target_changed if the package switched to its private copy after
the plan was shown. Uninstall removes REA from both files.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(setup): record the verified MSIX Claude Desktop registration
On the Windows 11 host with the MSIX build 2.31226.1.0, setup from an
ordinary terminal with the app quit wrote the package-private copy. After
the app restarted, the entry persisted, doctor reported it aligned, and
Claude Desktop's MCP log showed REA starting and answering tools/list.
Uninstall against the real app remains unverified.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* style(setup): format MSIX review corrections
* fix(setup): carry the admitted legacy path through uninstall removal
clientRegistrationRemoval returned a removeLegacy boolean, and removeClient
recomputed the legacy path separately, so TypeScript could not prove the
path existed when removeLegacy was true and `tsc --noEmit` failed in
Uninstall.ts. The decision now returns the admitted legacy path itself;
preflight and removal consume that one value.
The alias regression matched new-destination children with a "/"
separator while building paths with path.join, so it failed on Windows.
It now uses path.sep.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(setup): split MSIX Claude Desktop lifecycle cases under the function length limit
The uninstall cases pushed the registration lifecycle describe past the 150-line lint limit. Group them separately, with the AppData registration case kept among the registration cases.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(native): bound captured output carried by native command failures
The native command runner retains up to 64 MiB of output because
successful analysis needs it complete, and failureCapture copied all of
it into the failure. An inspect_plist whose plutil output exceeded the
budget therefore returned a 67 MB resource_constraint error whose
details.captured_output.stdout repeated the whole retained output.
Keep a 64 KiB UTF-8-safe excerpt per stream in failure diagnostics,
mark them truncated, and keep the observed stdout/stderr byte totals.
Successful captures are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(native): bound codesign failures and cover excerpt cuts
translateCodeSignExitFailure wrapped an accepted nonzero codesign capture
into a NativeCommandFailure by copying both complete streams, so
inspect_signature failures still bypassed the diagnostic bound. Route it
through the shared failureCapture builder; accepted output stays
complete until the provider decides it is a failure.
Add a focused runner test for an ordinary nonzero exit with stdout and
stderr just above the excerpt size and a two-byte character straddling
the cut, and a provider test for the codesign path.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(native): build excerpt test output inside the child process
The output strings embedded in one node -e argument totalled about 133
KB, above Linux's 128 KiB per-argument limit, so spawn failed with E2BIG
on the CI runner. Generate the repeated output in the child instead.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(reconstruction): reject contradictory function comparison status
* test(reconstruction): cover imported function match precedence
---------
Co-authored-by: maxazure <405711+maxazure@users.noreply.github.com>
* fix(apktool): resolve Windows PATH launchers before invocation
Resolve the default launcher through the selected PATH/PATHEXT before choosing native process creation or the existing conservative cmd.exe wrapper. Reuse the resulting selection and one canonical environment for the version probe and decode.
Follow-up to the release #1693 review of #1777. Source inspected and formatted; tests, builds, check reruns and real Windows Apktool execution were skipped at maintainer request.
* fix(apktool): bound lookup and retain only selected environment
Source inspection and targeted formatting only. Tests, builds, lint, typechecks and provider workloads were not run at the user's explicit request.
* fix(apktool): use supported timeout diagnostics
Retain lookup phase through AnalysisErrorOptions diagnostics while preserving the operation and timeout identity. Source inspection and targeted formatting only; tests, checks, builds and provider workloads were skipped at the user request.
---------
Co-authored-by: morluto <morluto@users.noreply.github.com>
observe-native-ui and capture-native-ui-scenario were registered in one
loop with a shared option schema and description. The passive command
therefore advertised `--steps` ("Observe or run a scenario"), accepted
any value, and then dispatched observe_native_ui without it, so a
caller who selected the wrong command never learned that no scenario ran.
Register each command against its own contract. Observation declares
only the passive scope options, so `--steps` is rejected as an unknown
flag; the scenario command keeps its JSON step decoding and validation.
Each command now has its own description.
Fixes#2674
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A profile mismatch reached the caller as a bare AnalysisProtocolError,
which projects to `unreadable_output` with a generic message. The error
already named every missing tool, but none of that detail survived, so
the only way to identify the cause was to log the JSON-RPC traffic and
notice the exchange stopping after `tools/list`.
Throw a ProviderAdapterError instead, carrying the mode, the expected
profile and the missing tool names through the diagnostics channel that
already surfaces in `details`. Document which upstream versions each
profile accepts, since upstream `main` now serves neither.
Refs #2301
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(flutter): name a missing or non-file APK selection
identify_flutter_build and inspect_dart_aot reported a missing path or a
directory as "The APK could not be read as a package: <path>: ENOENT ...",
which blames the package bytes for a selection mistake. Report
"Selected APK does not exist" for ENOENT/ENOTDIR and "Selected APK is not
a regular file" for a non-regular selection, matching the SQLite
inspector's wording. The issue path and invalid_format reason are
unchanged; package format failures keep their existing message.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(filesystem): classify unopenable non-regular selections at admission
A Unix socket cannot be opened at all: open() fails with ENXIO on Linux
and EOPNOTSUPP on macOS (surfaced by libuv as "Unknown system error
-102") before openRegularFile can stat the descriptor, so such a
selection escaped NonRegularFileReadError and the Flutter provider still
blamed the package bytes.
When open fails, classify the path by its own metadata (lstat when
symlinks are rejected, stat otherwise): an existing non-regular file
becomes NonRegularFileReadError. Missing paths, permission failures,
regular files, and the O_NOFOLLOW ELOOP rejection keep their original
errors. The Flutter selection test now covers a real Unix socket.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(filesystem): reclassify only unopenable file-type errors at admission
Checking the path's metadata after any open failure turned EACCES on an
unreadable directory into NonRegularFileReadError, so callers reported
invalid input instead of access_denied. Reclassify only errors that mean
the file type cannot be opened (ENXIO, EOPNOTSUPP, ENOTSUP, matched by
errno because libuv has no name for macOS EOPNOTSUPP 102); permission,
symlink-rejection and resource failures keep their original errors.
Run the Unix socket selection check in its own test, skipped on Windows
where listen() takes named pipes, and keep the missing-path and
directory checks cross-platform.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(filesystem): keep cancellation that arrives during the non-regular probe
A caller abort while the post-open metadata probe ran was replaced by
NonRegularFileReadError, so callers such as parseBinaryTarget reported an
input-format error instead of cancellation. Recheck the signal before
substituting the non-regular classification.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(sqlite): classify a missing database path as an invalid value
The snapshot reported an absent selected database as an artifact path
failure, which the adapter projects as invalid_format alongside malformed
paths and content. The snapshot owns the absence observation, so it now
returns an invalid_value input issue on path directly, matching the
adapter's existing ENOENT/ENOTDIR classification.
Fixes#2614
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(sqlite): classify a missing database path as an invalid value
The snapshot reported an absent selected database as an artifact path
failure, which the adapter projects as invalid_format alongside malformed
paths and content. The snapshot owns the absence observation, so it now
returns an invalid_value input issue on path directly, matching the
adapter's existing ENOENT/ENOTDIR classification.
Fixes#2614
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Pass the tool contract's `returnsTargetContent` to
`toRecordedPartialErrorToolResult` in the shared Evidence handler, matching
the Electron call site.
The call site that records a retained partial observation was added without
the argument required by the untrusted target-content framing, so the
delivery neither marked the result nor counted the provenance marker in its
wire budget. The type gate failed on main with
`contractToolHandler.ts(69,38): error TS2554`, which also blocked every
compiled boundary test lane.