Compare commits

...
Author SHA1 Message Date
Beqa d4a7c20e04 docs: clarify coordination for overlapping PR fixes (#8931)
Say how to point at an overlapping change and then rebase, narrow, or close it, without implying a review date.
2026-11-10 02:13:39 +00:00
2SinceJuly 27edc5c83f test(ghidra): assert projected limitations instead of a stale literal (#9268)
Project analyze_function limitations from the provider instead of a sentence #9246 removed, so the boundary test follows the producer and main CI can go green.
2026-11-10 02:13:16 +00:00
ShuaixinHuang c52a9b9d79 fix(pe): reject misaligned certificate table offsets (#9666)
* fix(pe): reject misaligned certificate table offsets

* test: align ghidra limitation wording with main

* style: format ghidra limitation assertion

* test(ghidra): assert current provider limitations
2026-11-09 17:31:41 -05:00
morluto 8dfc47b107 fix(ci): restore compilation and static checks on main 2026-11-09 16:11:47 -05:00
ShuaixinHuangandFelix e9b6c87c1c fix(cli): align ADB package-name schemas (#9675)
Co-authored-by: Felix <[email protected]>
2026-11-09 10:28:15 -05:00
387bcb795d feat(desktop): isolate declared secrets during app builds (#9225)
* fix(desktop): preserve local file URL authority

* fix(desktop): preserve local file URL authority

* fix(desktop): preserve local file URL authority

* fix(desktop): render captured file URLs at launch

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): retain context for generated draft values

* fix(desktop): retain context for generated draft values

* fix(desktop): retain context for generated draft values

* test(desktop): cover generated IDs in text guards

* test(desktop): cover generated IDs in text guards

* test(desktop): cover generated IDs in text guards

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): bound private key redaction spans

* fix(desktop): retain published bundle on copy failure

* fix(desktop): retain secret file cleanup owners

* fix(desktop): retain both published output cleanup owners

* test(desktop): verify UTF-16 credential refusal

* test(desktop): verify truncated secret redaction over MCP

* fix(desktop): retain clean text in noisy record fields

* fix(desktop): classify added line values in one pass

* fix(desktop): scan private key runs in one pass

* fix(desktop): apply XML quote rules to text drafts

* fix(desktop): distinguish XML attributes from quoted text

* fix(desktop): preserve parsed XML line context

* Format appTaskChecks.ts with the pinned oxfmt

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(desktop): retain partial XML syntax facts

* fix(desktop): recognize markdown autolinks in drafts

* fix(desktop): reuse export exclusions in task drafts

* fix(desktop): report unchecked client build paths

* docs(desktop): clarify gzip scrub limits

* test(desktop): build the fixture JWT from its parts and reformat

The literal token made every edit of this file trip secret scanners; the test
checks the same string. Also applies the pinned oxfmt to the key-run test.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(desktop): reuse export exclusions in task drafts

* docs(desktop): clarify gzip scrub limits

* fix(setup): own desktop build process cleanup

* fix(desktop): find no private key in NSS's key4.db password check

An Electron app's NSS key database holds a password-check value shaped like
an encrypted private key, so every such export was refused. An encrypted key
now counts only under a password-based encryption scheme, never PBKDF2 or
PBMAC1, and with at least the 48 bytes of encrypted data the smallest key
needs.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(doctor): compare desktop settings with resolved defaults

* style(desktop): format the noisy-record draft files with the pinned oxfmt

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* test(desktop): give the root-array draft test its own describe

The records describe grew past the 150-line lint limit with it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(doctor): inspect client-recorded desktop runners

* fix(doctor): reuse matching runner probes

* fix(setup): propagate cancellation to desktop actions

* fix(setup): stop Hopper on cancel, never report a cancelled setup ready, and keep a failed action's client setting

- The Hopper install gets setup's signal: Linux already honoured it, and the
  macOS installer now stops its downloads and stops before mounting or copying.
- runSetup checks the signal after the final doctor and close, so a
  cancellation there raises instead of returning ready.
- A failed pack or agentenv install no longer writes its archive or runner to
  client configs, so the setting the client already had stays.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(desktop): close five withheld-state gaps a review found

- A sign-in window whose walk hit its entry limit, could not read a path or
  left a change unconfirmed is refused, rather than trusted as complete.
- The export refuses app dconf keys the sign-in window changed and the seed
  would ship with a different value, naming the keys, not their values.
- A bundle holding a gzip file that expands past what REA scans is refused.
- Withheld bytes are kept under a handle of their own, created exclusively and
  never replaced; a later build's different bytes take the next free handle,
  and a handle the computer's answer names is checked before any write.
- Setting names a Python keyword or a leading digit would break get file_,
  and names that collide get _2, _3 in a stable order.
- Adds the feature's tasks.md.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(desktop): redact a cut secret's start only at REA's own cuts

The boundary match for a secret cut short hid the start of any ellipsis-ended
text, so "Please…" became a redaction. It now applies only where text ends
one of REA's value cuts, whose lengths the producers and the redactor share,
and the host redacts the app's stderr and progress before it quotes their
end. Redacting before anything cuts stays a follow-up.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(setup): keep the completed setup result in a cancellation after cleanup

A cancellation during the final doctor or host close carried only the applied
actions, dropping each client's result and backup path and the doctor report.
It now carries the whole result as setup_result, as doctor's cancellation
carries its report.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(desktop): publish secret files atomically, decompress a gzip seed once, and scan JSON strings linearly

- A secret file is written under a private temporary name and linked to its
  handle, so a concurrent export never reads a half-written file and reuses
  its handle for other bytes.
- The export decompresses each gzip seed file once and shares the result
  with the secret scan, the credential scan and the size refusal.
- The cut-secret stopgap finds JSON string literals in one forward pass
  instead of restarting at every quote.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* test(desktop): move launch execution to boundary suite

* fix(desktop): redact build schema failure output

* refactor(desktop): normalize schema failure once

* fix(desktop): omit unsafe schema parser snippets

* fix(desktop): preserve draft change and selected path evidence

* test(desktop): group retained dconf note regressions

* fix(desktop): respect archive entry format in draft checks

* test(desktop): separate unowned-file draft note cases

* fix(desktop): preserve explicitly selected journal documents

* fix(xml): avoid scanning selected ancestors per tag

* fix(desktop): exclude covered text runs from draft counts

* fix: preserve text when drafting desktop checks

* fix: restore nested desktop state aliases

* refactor: share UUID recognition across draft checks

* fix: retain multiline XML attribute context

* fix: retain relationship identifiers in task drafts

* docs: clarify desktop draft identifier handling

* test(desktop): type formatting run cases as pairs

* fix(desktop): carry document format into selector evaluation

* test(desktop): separate markup boundary regression group

* fix(desktop): propagate formats through draft selectors

* fix(desktop): switch selector format within archive entries

* test(desktop): remove duplicate seed filename case

* fix(setup): retain diagnostics when cancellation overlaps failure

* refactor(setup): keep command cancellation at its owner

* test(setup): verify cancellation at the application boundary

* test(desktop): pass JSON format in exported index parity

* docs(desktop): clarify task checks before scratch export

* fix(desktop): respell selected paths in file URLs

* test(desktop): group captured document spelling cases

* fix(desktop): retain temporary secret file cleanup

* fix(desktop): preserve unmarked token-shaped values

* fix(desktop): withhold drafts after secret use

* fix(desktop): guard drafts against shared secret changes

* test(desktop): compare preserved seed bytes without enumeration

* fix(desktop): bound draft preview serialization

* fix(desktop): restore selected state aliases

* fix(desktop): respect entry format in draft noise

* test(desktop): match exported alias evidence at its JSON boundary

* fix(desktop): retain app state logs in exported seeds

* fix: align desktop numeric seed comparisons

* test(desktop): keep one draft exclusion fixture import

* test(desktop): retain log eligibility across draft test groups

* fix(doctor): resolve empty registered desktop runner

* style: fix desktop launch test formatting

* style: format native command path schema

* fix(desktop): map selected external launch paths

* style(desktop): format seed document regressions

* test(desktop): group launch URL regressions

* fix(desktop): omit redundant nested state aliases

* fix(desktop): compare added free text as a whole

* fix(desktop): check recompressed seeds as shipped

* docs(desktop): clarify recovered seed format

* test(desktop): group shipped gzip seed checks

* fix: retain quoted identifier text in task drafts

* fix: recognize Unicode XML in desktop state readers

* fix(desktop): bound nested draft checks

* fix(desktop): explain missing arrays in truncated views

* fix(desktop): find XML type references in archives

* test(desktop): remove duplicated capture assertions

* fix(desktop): retain nested omitted text boundaries

* style(desktop): format draft value imports

* test(desktop): group model and draft value checks

* fix(desktop): map captured launch paths once

* refactor: remove unused whole-text guard state

* refactor: stop passing unused text children

* test: align free-text checks with whole-note policy

* fix: validate recompressed desktop archive seeds

* style(desktop): format archive seed regression

* fix(desktop): retain placed-item sibling guards

* fix(desktop): preserve archive paths and bound doctor reads

* fix(doctor): refuse non-files before descriptor admission

* fix(setup): track remaining cleanup resources across retries

* test(desktop): specify XML format in heap pairing fixture

* fix(doctor): query agentenv for model endpoint

* fix(doctor): preserve uncertainty for empty endpoint override

* fix(desktop): protect host controls and quote withheld paths

* fix: redact declared form-encoded secrets

* fix(desktop): redact runtime schema errors

* fix(desktop): normalize captured file URLs

* fix(desktop): report seeded files by capture path

* fix(desktop): retain startup readiness failure stage

* fix(desktop): retain JSON date checks

* fix(desktop): preserve archive formatting checks

* fix(desktop): preserve explicitly selected journal files

* fix(desktop): report build command transport limits

* docs(desktop): clarify unreadable dconf versions

* test(desktop): remove duplicate history regression

* fix(desktop): align XML names with exported reader

* fix(desktop): create selected state alias targets

* fix(desktop): inspect supported runtime archives

* fix(desktop): retain record identity in draft checks

* fix(desktop): refuse unchecked declared secrets

* fix(desktop): retain partial withheld export receipts

* fix(desktop): detect escaped secrets in JSON state

* fix(desktop): scrub XML independently of reader compatibility

* fix(desktop): preserve file aliases and reader diagnostics

* fix(desktop): scan escaped secrets in UTF-16 JSON

* style(desktop): format secret scan changes

* style(desktop): format review fixes

* style(desktop): format capture review fixes

* style(desktop): format review changes

---------

Co-authored-by: morluto <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-09 23:23:13 +08:00
Ryan S e5ddbe8909 feat(native): decode Android .note.android.ident ELF notes (#9502)
* feat(native): decode Android .note.android.ident ELF notes

Decode Android NDK NT_ANDROID_TYPE_IDENT (.note.android.ident, owner Android, type 1) notes in inspect_elf_notes across legacy 4-byte and modern >=132-byte descriptors with bounded TextBudget accounting.

* fix(native): isolate Android note scan budget test, scope contract import, and add feature spec

* test(native): use domain tool contract in elfNotesMcp boundary test
2026-11-09 10:21:38 -05:00
018f19d8c8 feat(desktop): target agentenv-framework 0.9.1464 (#9302)
* fix(desktop): preserve document URLs and value formats

* fix(desktop): bound added checks and omit noisy text guards

* fix(desktop): exclude unseeded locks from task checks

* fix(desktop): preserve draft bounds and launch URLs

* fix(desktop): render draft values using their source format

* fix(desktop): preserve launch URLs and JSON draft values

* fix(desktop): recognize captured file URL documents

* fix(desktop): render captured file URLs for runtime home

* fix(desktop): distinguish phone numbers from save metadata

* fix(desktop): preserve launch URLs and user text

* fix(desktop): preserve captured URLs and user text

* fix(desktop): preserve local file URL authority

* fix(desktop): preserve local file URL authority

* fix(desktop): preserve local file URL authority

* fix(desktop): render captured file URLs at launch

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): retain context for generated draft values

* fix(desktop): retain context for generated draft values

* fix(desktop): retain context for generated draft values

* test(desktop): cover generated IDs in text guards

* test(desktop): cover generated IDs in text guards

* test(desktop): cover generated IDs in text guards

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): retain clean text in noisy record fields

* fix(desktop): classify added line values in one pass

* fix(desktop): apply XML quote rules to text drafts

* fix(desktop): distinguish XML attributes from quoted text

* fix(desktop): preserve parsed XML line context

* Format appTaskChecks.ts with the pinned oxfmt

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(desktop): retain partial XML syntax facts

* feat(desktop): target agentenv-framework 0.9.1464

Desktop bundles, setup's --install-agentenv and the doctor's exact-version
check now target 0.9.1464, which keeps an exported app's data/get call,
holds the computer fixture above boot dialogs, leaves an unresolved setting's
build unverified rather than failed, and mounts lock packages instead of
copying them into the image. The web environment lane stays on 0.9.1431.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(desktop): recognize markdown autolinks in drafts

* fix(desktop): reuse export exclusions in task drafts

* fix(desktop): reuse export exclusions in task drafts

* fix(desktop): report unchecked client build paths

* docs(desktop): clarify gzip seed scrubbing

* fix(desktop): report unchecked client build paths

* docs(desktop): clarify gzip scrub limits

* fix(desktop): reuse export exclusions in task drafts

* docs(desktop): clarify gzip scrub limits

* fix(setup): own desktop build process cleanup

* fix(setup): own desktop build process cleanup

* fix(doctor): compare desktop settings with resolved defaults

* fix(doctor): compare desktop settings with resolved defaults

* style(desktop): format the noisy-record draft files with the pinned oxfmt

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* test(desktop): give the root-array draft test its own describe

The records describe grew past the 150-line lint limit with it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(doctor): inspect client-recorded desktop runners

* fix(doctor): inspect client-recorded desktop runners

* fix(doctor): reuse matching runner probes

* fix(doctor): reuse matching runner probes

* fix(setup): propagate cancellation to desktop actions

* fix(setup): propagate cancellation to desktop actions

* fix(setup): stop Hopper on cancel, never report a cancelled setup ready, and keep a failed action's client setting

- The Hopper install gets setup's signal: Linux already honoured it, and the
  macOS installer now stops its downloads and stops before mounting or copying.
- runSetup checks the signal after the final doctor and close, so a
  cancellation there raises instead of returning ready.
- A failed pack or agentenv install no longer writes its archive or runner to
  client configs, so the setting the client already had stays.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(setup): keep the completed setup result in a cancellation after cleanup

A cancellation during the final doctor or host close carried only the applied
actions, dropping each client's result and backup path and the doctor report.
It now carries the whole result as setup_result, as doctor's cancellation
carries its report.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* test(desktop): move launch execution to boundary suite

* fix(desktop): redact build schema failure output

* refactor(desktop): normalize schema failure once

* fix(desktop): omit unsafe schema parser snippets

* fix(desktop): preserve draft change and selected path evidence

* test(desktop): group retained dconf note regressions

* fix(desktop): respect archive entry format in draft checks

* test(desktop): separate unowned-file draft note cases

* fix(desktop): preserve explicitly selected journal documents

* fix(xml): avoid scanning selected ancestors per tag

* fix(desktop): exclude covered text runs from draft counts

* fix: preserve text when drafting desktop checks

* fix: restore nested desktop state aliases

* refactor: share UUID recognition across draft checks

* fix: retain multiline XML attribute context

* fix: retain relationship identifiers in task drafts

* docs: clarify desktop draft identifier handling

* test(desktop): type formatting run cases as pairs

* fix(desktop): carry document format into selector evaluation

* test(desktop): separate markup boundary regression group

* fix(desktop): propagate formats through draft selectors

* fix(desktop): switch selector format within archive entries

* test(desktop): remove duplicate seed filename case

* fix(setup): retain diagnostics when cancellation overlaps failure

* refactor(setup): keep command cancellation at its owner

* test(setup): verify cancellation at the application boundary

* test(desktop): pass JSON format in exported index parity

* docs(desktop): clarify task checks before scratch export

* fix(desktop): respell selected paths in file URLs

* test(desktop): group captured document spelling cases

* fix(desktop): bound draft preview serialization

* fix(desktop): restore selected state aliases

* fix(desktop): respect entry format in draft noise

* test(desktop): match exported alias evidence at its JSON boundary

* fix(desktop): retain app state logs in exported seeds

* fix: align desktop numeric seed comparisons

* test(desktop): keep one draft exclusion fixture import

* test(desktop): retain log eligibility across draft test groups

* fix(doctor): resolve empty registered desktop runner

* test(desktop): use the framework pin in doctor fixtures

* style: fix desktop launch test formatting

* style: format native command path schema

* fix(desktop): map selected external launch paths

* style(desktop): format seed document regressions

* test(desktop): group launch URL regressions

* fix(desktop): omit redundant nested state aliases

* fix(desktop): compare added free text as a whole

* fix(desktop): check recompressed seeds as shipped

* docs(desktop): clarify recovered seed format

* test(desktop): group shipped gzip seed checks

* fix: retain quoted identifier text in task drafts

* fix: recognize Unicode XML in desktop state readers

* fix(desktop): bound nested draft checks

* fix(desktop): explain missing arrays in truncated views

* fix(desktop): find XML type references in archives

* test(desktop): remove duplicated capture assertions

* fix(desktop): retain nested omitted text boundaries

* style(desktop): format draft value imports

* test(desktop): group model and draft value checks

* fix(desktop): map captured launch paths once

* refactor: remove unused whole-text guard state

* refactor: stop passing unused text children

* test: align free-text checks with whole-note policy

* fix: validate recompressed desktop archive seeds

* style(desktop): format archive seed regression

* fix(desktop): retain placed-item sibling guards

* fix(desktop): preserve archive paths and bound doctor reads

* fix(doctor): refuse non-files before descriptor admission

* fix(setup): track remaining cleanup resources across retries

* test(desktop): specify XML format in heap pairing fixture

* fix(doctor): query agentenv for model endpoint

* fix(doctor): preserve uncertainty for empty endpoint override

* style(desktop): format framework pin fixture

* fix(desktop): redact runtime schema errors

* fix(desktop): normalize captured file URLs

* fix(desktop): report seeded files by capture path

* fix(desktop): retain startup readiness failure stage

* fix(desktop): retain JSON date checks

* fix(desktop): preserve archive formatting checks

* fix(desktop): preserve explicitly selected journal files

* fix(desktop): report build command transport limits

* docs(desktop): clarify unreadable dconf versions

* test(desktop): remove duplicate history regression

* fix(desktop): align XML names with exported reader

* fix(desktop): create selected state alias targets

* fix(desktop): inspect supported runtime archives

* fix(desktop): retain record identity in draft checks

* fix(desktop): inspect supported runtime archives

* fix(setup): retain completed actions on cancellation

* docs(desktop): clarify document lock exclusion

* fix(desktop): scrub XML independently of reader compatibility

* fix(desktop): preserve file aliases and reader diagnostics

* style(desktop): format review fixes

* style(desktop): format capture review fixes

* fix(desktop): retain merged installer behavior

---------

Co-authored-by: morluto <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-09 23:12:10 +08:00
fe2985a0b4 feat(desktop): check apps whose files REA can't read, through the app's own headless mode or a screen judge (#9217)
* fix(desktop): preserve document URLs and value formats

* fix(desktop): bound added checks and omit noisy text guards

* fix(desktop): exclude unseeded locks from task checks

* fix(desktop): preserve draft bounds and launch URLs

* fix(desktop): render draft values using their source format

* fix(desktop): preserve launch URLs and JSON draft values

* fix(desktop): recognize captured file URL documents

* fix(desktop): render captured file URLs for runtime home

* fix(desktop): distinguish phone numbers from save metadata

* fix(desktop): preserve launch URLs and user text

* fix(desktop): preserve captured URLs and user text

* fix(desktop): preserve local file URL authority

* fix(desktop): preserve local file URL authority

* fix(desktop): preserve local file URL authority

* fix(desktop): render captured file URLs at launch

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): retain context for generated draft values

* fix(desktop): retain context for generated draft values

* fix(desktop): retain context for generated draft values

* test(desktop): cover generated IDs in text guards

* test(desktop): cover generated IDs in text guards

* test(desktop): cover generated IDs in text guards

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): retain clean text in noisy record fields

* fix(desktop): classify added line values in one pass

* fix(desktop): apply XML quote rules to text drafts

* fix(desktop): distinguish XML attributes from quoted text

* fix(desktop): preserve parsed XML line context

* Format appTaskChecks.ts with the pinned oxfmt

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(desktop): retain partial XML syntax facts

* fix(desktop): recognize markdown autolinks in drafts

* fix(desktop): reuse export exclusions in task drafts

* fix(desktop): report unchecked client build paths

* docs(desktop): clarify gzip scrub limits

* fix(desktop): reuse export exclusions in task drafts

* docs(desktop): keep the judge command on one line

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* docs(desktop): clarify gzip scrub limits

* fix(setup): own desktop build process cleanup

* fix(doctor): compare desktop settings with resolved defaults

* style(desktop): format the noisy-record draft files with the pinned oxfmt

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* test(desktop): give the root-array draft test its own describe

The records describe grew past the 150-line lint limit with it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(doctor): inspect client-recorded desktop runners

* fix(doctor): reuse matching runner probes

* fix(setup): propagate cancellation to desktop actions

* fix(setup): stop Hopper on cancel, never report a cancelled setup ready, and keep a failed action's client setting

- The Hopper install gets setup's signal: Linux already honoured it, and the
  macOS installer now stops its downloads and stops before mounting or copying.
- runSetup checks the signal after the final doctor and close, so a
  cancellation there raises instead of returning ready.
- A failed pack or agentenv install no longer writes its archive or runner to
  client configs, so the setting the client already had stays.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(setup): keep the completed setup result in a cancellation after cleanup

A cancellation during the final doctor or host close carried only the applied
actions, dropping each client's result and backup path and the doctor report.
It now carries the whole result as setup_result, as doctor's cancellation
carries its report.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* test(desktop): move launch execution to boundary suite

* fix(desktop): redact build schema failure output

* refactor(desktop): normalize schema failure once

* fix(desktop): omit unsafe schema parser snippets

* fix(desktop): preserve draft change and selected path evidence

* test(desktop): group retained dconf note regressions

* fix(desktop): respect archive entry format in draft checks

* test(desktop): separate unowned-file draft note cases

* fix(desktop): preserve explicitly selected journal documents

* fix(xml): avoid scanning selected ancestors per tag

* fix(desktop): exclude covered text runs from draft counts

* fix: preserve text when drafting desktop checks

* fix: restore nested desktop state aliases

* refactor: share UUID recognition across draft checks

* fix: retain multiline XML attribute context

* fix: retain relationship identifiers in task drafts

* docs: clarify desktop draft identifier handling

* test(desktop): type formatting run cases as pairs

* fix(desktop): carry document format into selector evaluation

* test(desktop): separate markup boundary regression group

* fix(desktop): propagate formats through draft selectors

* fix(desktop): switch selector format within archive entries

* test(desktop): remove duplicate seed filename case

* fix(setup): retain diagnostics when cancellation overlaps failure

* refactor(setup): keep command cancellation at its owner

* test(setup): verify cancellation at the application boundary

* test(desktop): pass JSON format in exported index parity

* docs(desktop): clarify task checks before scratch export

* fix(desktop): respell selected paths in file URLs

* test(desktop): group captured document spelling cases

* test(desktop): pin reader-free verifier to selector parent

* fix(desktop): bound draft preview serialization

* fix(desktop): restore selected state aliases

* fix(desktop): respect entry format in draft noise

* test(desktop): match exported alias evidence at its JSON boundary

* fix(desktop): retain app state logs in exported seeds

* fix: align desktop numeric seed comparisons

* test(desktop): keep one draft exclusion fixture import

* test(desktop): retain log eligibility across draft test groups

* fix(doctor): resolve empty registered desktop runner

* test(desktop): check retained log seed admission

* style: fix desktop launch test formatting

* style: format native command path schema

* fix(desktop): map selected external launch paths

* style(desktop): format seed document regressions

* test(desktop): group launch URL regressions

* fix(desktop): omit redundant nested state aliases

* fix(desktop): compare added free text as a whole

* fix(desktop): check recompressed seeds as shipped

* docs(desktop): clarify recovered seed format

* test(desktop): group shipped gzip seed checks

* fix: retain quoted identifier text in task drafts

* fix: recognize Unicode XML in desktop state readers

* fix(desktop): bound nested draft checks

* fix(desktop): explain missing arrays in truncated views

* fix(desktop): find XML type references in archives

* test(desktop): remove duplicated capture assertions

* fix(desktop): retain nested omitted text boundaries

* style(desktop): format draft value imports

* test(desktop): group model and draft value checks

* fix(desktop): map captured launch paths once

* refactor: remove unused whole-text guard state

* refactor: stop passing unused text children

* test: align free-text checks with whole-note policy

* fix: validate recompressed desktop archive seeds

* style(desktop): format archive seed regression

* fix(desktop): retain placed-item sibling guards

* fix(desktop): preserve archive paths and bound doctor reads

* fix(doctor): refuse non-files before descriptor admission

* fix(setup): track remaining cleanup resources across retries

* test(desktop): specify XML format in heap pairing fixture

* fix(desktop): compare screen task views by value

* fix(desktop): reject inexact reader numbers

* fix(desktop): budget export for both reader passes

* fix(desktop): bound reader runner argument size

* test(desktop): verify chunked reader payloads and parent output

* fix(doctor): query agentenv for model endpoint

* style(desktop): format reader payload assertion

* fix(doctor): preserve uncertainty for empty endpoint override

* fix(desktop): redact runtime schema errors

* fix(desktop): normalize captured file URLs

* fix(desktop): report seeded files by capture path

* fix(desktop): retain startup readiness failure stage

* fix(desktop): retain JSON date checks

* fix(desktop): preserve archive formatting checks

* fix(desktop): preserve explicitly selected journal files

* fix(desktop): report build command transport limits

* docs(desktop): clarify unreadable dconf versions

* test(desktop): remove duplicate history regression

* fix(desktop): align XML names with exported reader

* fix(desktop): create selected state alias targets

* fix(desktop): inspect supported runtime archives

* fix(desktop): retain record identity in draft checks

* fix(desktop): align timestamp selector digits

* fix(desktop): scrub XML independently of reader compatibility

* fix(desktop): preserve file aliases and reader diagnostics

* fix(desktop): retain remote reader cleanup ownership

* style(desktop): format capture review fixes

* fix(desktop): retain reader leases across verifier reloads

* test(desktop): overlap reader cleanup retries

* fix(desktop): run long exports within exec limits

---------

Co-authored-by: morluto <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-09 23:09:52 +08:00
26d81afedd feat(desktop): install an app from an AppImage or an upstream tarball, pinned by its SHA-256 (#9215)
* fix(desktop): recognize captured file URL documents

* fix(desktop): render captured file URLs for runtime home

* fix(desktop): distinguish phone numbers from save metadata

* fix(desktop): preserve launch URLs and user text

* fix(desktop): preserve captured URLs and user text

* fix(desktop): preserve local file URL authority

* fix(desktop): preserve local file URL authority

* fix(desktop): preserve local file URL authority

* fix(desktop): render captured file URLs at launch

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): retain context for generated draft values

* fix(desktop): retain context for generated draft values

* fix(desktop): retain context for generated draft values

* test(desktop): cover generated IDs in text guards

* test(desktop): cover generated IDs in text guards

* test(desktop): cover generated IDs in text guards

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): retain clean text in noisy record fields

* fix(desktop): classify added line values in one pass

* fix(desktop): apply XML quote rules to text drafts

* fix(desktop): distinguish XML attributes from quoted text

* fix(desktop): preserve parsed XML line context

* Format appTaskChecks.ts with the pinned oxfmt

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(desktop): retain partial XML syntax facts

* fix(desktop): recognize markdown autolinks in drafts

* fix(desktop): reuse export exclusions in task drafts

* fix(desktop): report unchecked client build paths

* docs(desktop): clarify gzip scrub limits

* fix(desktop): reuse export exclusions in task drafts

* docs(desktop): clarify gzip scrub limits

* fix(setup): own desktop build process cleanup

* fix(doctor): compare desktop settings with resolved defaults

* style(desktop): format the noisy-record draft files with the pinned oxfmt

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* test(desktop): give the root-array draft test its own describe

The records describe grew past the 150-line lint limit with it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(doctor): inspect client-recorded desktop runners

* fix(doctor): reuse matching runner probes

* fix(setup): propagate cancellation to desktop actions

* fix(desktop): rewrite a download's launch keys written with spaces around =

The desktop entry parser accepts `Exec = notes %F` and an indented
`TryExec =notes`, so the install script now matches those keys the same way
instead of leaving the original program in place. Adds the feature's tasks.md.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(setup): stop Hopper on cancel, never report a cancelled setup ready, and keep a failed action's client setting

- The Hopper install gets setup's signal: Linux already honoured it, and the
  macOS installer now stops its downloads and stops before mounting or copying.
- runSetup checks the signal after the final doctor and close, so a
  cancellation there raises instead of returning ready.
- A failed pack or agentenv install no longer writes its archive or runner to
  client configs, so the setting the client already had stays.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(setup): keep the completed setup result in a cancellation after cleanup

A cancellation during the final doctor or host close carried only the applied
actions, dropping each client's result and backup path and the doctor report.
It now carries the whole result as setup_result, as doctor's cancellation
carries its report.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* test(desktop): move launch execution to boundary suite

* fix(desktop): redact build schema failure output

* refactor(desktop): normalize schema failure once

* fix(desktop): omit unsafe schema parser snippets

* fix(desktop): preserve draft change and selected path evidence

* test(desktop): group retained dconf note regressions

* fix(desktop): respect archive entry format in draft checks

* test(desktop): separate unowned-file draft note cases

* fix(desktop): preserve explicitly selected journal documents

* fix(xml): avoid scanning selected ancestors per tag

* fix(desktop): exclude covered text runs from draft counts

* fix: preserve text when drafting desktop checks

* fix: restore nested desktop state aliases

* refactor: share UUID recognition across draft checks

* fix: retain multiline XML attribute context

* fix: retain relationship identifiers in task drafts

* docs: clarify desktop draft identifier handling

* test(desktop): type formatting run cases as pairs

* fix(desktop): carry document format into selector evaluation

* test(desktop): separate markup boundary regression group

* fix(desktop): propagate formats through draft selectors

* fix(desktop): switch selector format within archive entries

* test(desktop): remove duplicate seed filename case

* fix(setup): retain diagnostics when cancellation overlaps failure

* refactor(setup): keep command cancellation at its owner

* test(setup): verify cancellation at the application boundary

* test(desktop): pass JSON format in exported index parity

* docs(desktop): clarify task checks before scratch export

* fix(desktop): respell selected paths in file URLs

* test(desktop): group captured document spelling cases

* test(desktop): run installer scripts at boundary

* style(desktop): remove trailing blank line

* fix(desktop): bound draft preview serialization

* fix(desktop): restore selected state aliases

* fix(desktop): respect entry format in draft noise

* test(desktop): match exported alias evidence at its JSON boundary

* fix(desktop): retain app state logs in exported seeds

* fix: align desktop numeric seed comparisons

* test(desktop): keep one draft exclusion fixture import

* test(desktop): retain log eligibility across draft test groups

* fix(doctor): resolve empty registered desktop runner

* style: fix desktop launch test formatting

* style: format native command path schema

* fix(desktop): map selected external launch paths

* style(desktop): format seed document regressions

* test(desktop): group launch URL regressions

* fix(desktop): omit redundant nested state aliases

* fix(desktop): compare added free text as a whole

* fix(desktop): check recompressed seeds as shipped

* docs(desktop): clarify recovered seed format

* test(desktop): group shipped gzip seed checks

* fix: retain quoted identifier text in task drafts

* fix: recognize Unicode XML in desktop state readers

* fix(desktop): bound nested draft checks

* fix(desktop): explain missing arrays in truncated views

* fix(desktop): find XML type references in archives

* test(desktop): remove duplicated capture assertions

* fix(desktop): retain nested omitted text boundaries

* style(desktop): format draft value imports

* test(desktop): group model and draft value checks

* fix(desktop): map captured launch paths once

* refactor: remove unused whole-text guard state

* refactor: stop passing unused text children

* test: align free-text checks with whole-note policy

* fix: validate recompressed desktop archive seeds

* style(desktop): format archive seed regression

* fix(desktop): retain placed-item sibling guards

* fix(desktop): preserve archive paths and bound doctor reads

* fix(doctor): refuse non-files before descriptor admission

* fix(setup): track remaining cleanup resources across retries

* test(desktop): specify XML format in heap pairing fixture

* fix(setup): skip Hopper launch after cancelled copy

* fix(doctor): query agentenv for model endpoint

* fix(doctor): preserve uncertainty for empty endpoint override

* fix(desktop): redact runtime schema errors

* fix(desktop): normalize captured file URLs

* fix(desktop): report seeded files by capture path

* fix(desktop): retain startup readiness failure stage

* fix(desktop): retain JSON date checks

* fix(desktop): preserve archive formatting checks

* fix(desktop): preserve explicitly selected journal files

* fix(desktop): report build command transport limits

* docs(desktop): clarify unreadable dconf versions

* test(desktop): remove duplicate history regression

* fix(desktop): align XML names with exported reader

* fix(desktop): create selected state alias targets

* fix(desktop): inspect supported runtime archives

* fix(desktop): keep ordinary text checks exact

* fix(desktop): verify registered build host paths

* fix(desktop): retain record identity in draft checks

* test(desktop): preserve text reference numbers

* fix(desktop): bound download install input reads

* fix(desktop): match placed notes by whole text

* fix(desktop): scrub XML independently of reader compatibility

* fix(desktop): preserve file aliases and reader diagnostics

* style(desktop): format review fixes

* fix(desktop): inspect archives with registered runner

* test(desktop): verify registered archive interpreter

* style(desktop): format capture review fixes

---------

Co-authored-by: morluto <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-09 23:06:05 +08:00
d71e35a5ae fix(desktop): find ids in archive entries and draft nothing for a state directory's lock (#9210)
* fix(desktop): align nested state selections with aliases

* fix(desktop): check build runtime export capability

* fix(desktop): provide complete runtime repack command

* fix(desktop): retain runtime probe failures

* test(desktop): identify capture independently of schema preflight

* fix(desktop): preserve document URLs and value formats

* fix(desktop): bound added checks and omit noisy text guards

* fix(desktop): exclude unseeded locks from task checks

* fix(desktop): preserve draft bounds and launch URLs

* fix(desktop): render draft values using their source format

* fix(desktop): preserve launch URLs and JSON draft values

* fix(desktop): recognize captured file URL documents

* fix(desktop): render captured file URLs for runtime home

* fix(desktop): distinguish phone numbers from save metadata

* fix(desktop): preserve launch URLs and user text

* fix(desktop): preserve captured URLs and user text

* fix(desktop): preserve local file URL authority

* fix(desktop): preserve local file URL authority

* fix(desktop): preserve local file URL authority

* fix(desktop): render captured file URLs at launch

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): retain context for generated draft values

* fix(desktop): retain context for generated draft values

* fix(desktop): retain context for generated draft values

* test(desktop): cover generated IDs in text guards

* test(desktop): cover generated IDs in text guards

* test(desktop): cover generated IDs in text guards

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): retain clean text in noisy record fields

* fix(desktop): classify added line values in one pass

* fix(desktop): apply XML quote rules to text drafts

* fix(desktop): distinguish XML attributes from quoted text

* fix(desktop): preserve parsed XML line context

* Format appTaskChecks.ts with the pinned oxfmt

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(desktop): retain partial XML syntax facts

* fix(desktop): recognize markdown autolinks in drafts

* fix(desktop): reuse export exclusions in task drafts

* fix(desktop): report unchecked client build paths

* docs(desktop): clarify gzip scrub limits

* fix(desktop): reuse export exclusions in task drafts

* docs(desktop): clarify gzip scrub limits

* fix(setup): own desktop build process cleanup

* fix(doctor): compare desktop settings with resolved defaults

* style(desktop): format the noisy-record draft files with the pinned oxfmt

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* test(desktop): give the root-array draft test its own describe

The records describe grew past the 150-line lint limit with it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(doctor): inspect client-recorded desktop runners

* fix(doctor): reuse matching runner probes

* fix(setup): propagate cancellation to desktop actions

* fix(setup): stop Hopper on cancel, never report a cancelled setup ready, and keep a failed action's client setting

- The Hopper install gets setup's signal: Linux already honoured it, and the
  macOS installer now stops its downloads and stops before mounting or copying.
- runSetup checks the signal after the final doctor and close, so a
  cancellation there raises instead of returning ready.
- A failed pack or agentenv install no longer writes its archive or runner to
  client configs, so the setting the client already had stays.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(setup): keep the completed setup result in a cancellation after cleanup

A cancellation during the final doctor or host close carried only the applied
actions, dropping each client's result and backup path and the doctor report.
It now carries the whole result as setup_result, as doctor's cancellation
carries its report.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* test(desktop): move launch execution to boundary suite

* fix(desktop): redact build schema failure output

* refactor(desktop): normalize schema failure once

* fix(desktop): omit unsafe schema parser snippets

* fix(desktop): preserve draft change and selected path evidence

* test(desktop): group retained dconf note regressions

* fix(desktop): respect archive entry format in draft checks

* test(desktop): separate unowned-file draft note cases

* fix(desktop): preserve explicitly selected journal documents

* fix(xml): avoid scanning selected ancestors per tag

* fix(desktop): exclude covered text runs from draft counts

* fix: preserve text when drafting desktop checks

* fix: restore nested desktop state aliases

* refactor: share UUID recognition across draft checks

* fix: retain multiline XML attribute context

* fix: retain relationship identifiers in task drafts

* docs: clarify desktop draft identifier handling

* test(desktop): type formatting run cases as pairs

* fix(desktop): carry document format into selector evaluation

* test(desktop): separate markup boundary regression group

* fix(desktop): propagate formats through draft selectors

* fix(desktop): switch selector format within archive entries

* test(desktop): remove duplicate seed filename case

* fix(setup): retain diagnostics when cancellation overlaps failure

* refactor(setup): keep command cancellation at its owner

* test(setup): verify cancellation at the application boundary

* test(desktop): pass JSON format in exported index parity

* docs(desktop): clarify task checks before scratch export

* fix(desktop): respell selected paths in file URLs

* test(desktop): group captured document spelling cases

* fix(desktop): bound draft preview serialization

* fix(desktop): restore selected state aliases

* fix(desktop): respect entry format in draft noise

* test(desktop): match exported alias evidence at its JSON boundary

* fix(desktop): retain app state logs in exported seeds

* fix: align desktop numeric seed comparisons

* test(desktop): keep one draft exclusion fixture import

* test(desktop): retain log eligibility across draft test groups

* fix(doctor): resolve empty registered desktop runner

* style: fix desktop launch test formatting

* style: format native command path schema

* fix(desktop): map selected external launch paths

* style(desktop): format seed document regressions

* test(desktop): group launch URL regressions

* fix(desktop): omit redundant nested state aliases

* fix(desktop): compare added free text as a whole

* fix(desktop): check recompressed seeds as shipped

* docs(desktop): clarify recovered seed format

* test(desktop): group shipped gzip seed checks

* fix: retain quoted identifier text in task drafts

* fix: recognize Unicode XML in desktop state readers

* fix(desktop): bound nested draft checks

* fix(desktop): explain missing arrays in truncated views

* fix(desktop): find XML type references in archives

* test(desktop): remove duplicated capture assertions

* fix(desktop): retain nested omitted text boundaries

* style(desktop): format draft value imports

* test(desktop): group model and draft value checks

* fix(desktop): map captured launch paths once

* refactor: remove unused whole-text guard state

* refactor: stop passing unused text children

* test: align free-text checks with whole-note policy

* fix: validate recompressed desktop archive seeds

* style(desktop): format archive seed regression

* fix(desktop): retain placed-item sibling guards

* fix(desktop): preserve archive paths and bound doctor reads

* fix(doctor): refuse non-files before descriptor admission

* fix(setup): track remaining cleanup resources across retries

* test(desktop): specify XML format in heap pairing fixture

* fix(doctor): query agentenv for model endpoint

* fix(doctor): preserve uncertainty for empty endpoint override

* fix(desktop): redact runtime schema errors

* fix(desktop): normalize captured file URLs

* fix(desktop): report seeded files by capture path

* fix(desktop): retain startup readiness failure stage

* fix(desktop): retain JSON date checks

* fix(desktop): preserve archive formatting checks

* fix(desktop): preserve explicitly selected journal files

* fix(desktop): report build command transport limits

* docs(desktop): clarify unreadable dconf versions

* test(desktop): remove duplicate history regression

* fix(desktop): align XML names with exported reader

* fix(desktop): create selected state alias targets

* fix(desktop): inspect supported runtime archives

* fix(desktop): keep ordinary text checks exact

* fix(desktop): verify registered build host paths

* fix(desktop): retain record identity in draft checks

* fix(desktop): scrub XML independently of reader compatibility

* fix(desktop): preserve file aliases and reader diagnostics

* style(desktop): format review fixes

* fix(desktop): inspect archives with registered runner

* test(desktop): verify registered archive interpreter

* style(desktop): format capture review fixes

---------

Co-authored-by: morluto <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-09 23:03:54 +08:00
240f08d406 feat(desktop): set up and check a desktop build host in one command (#9199)
* fix(desktop): keep an empty env value empty

An empty assignment is not a path. Resolving it named the working directory
and rewrote the value when that directory's spelling moved.

* fix(desktop): keep a run's font on the run, not the frame's text

A formatting attribute such as Scribus FONT is not the document's words.
Joining it across runs made a frame-wide text check of ItalicBold that
failed when a run was split. The font stays a value check on its own run.

* fix(desktop): do not pair JSON records by a selector-shaped field

A field named @record_id matched the id suffix and became [@record_id=one],
which reads an XML attribute. Records paired while their pointers matched
nothing. Names that start with @ or > are not id fields.

* fix(desktop): count a save-numbered id once when pairing members

xml:id and draw:id values such as id123456 were both generated and
numbered, so the same selector was counted twice and refused. A text
edit of two elements keyed only by those ids now keeps its check.

* fix(desktop): count members of root JSON arrays

* fix(desktop): preserve selected state directory aliases

* docs(desktop): explain tool and skill refresh prerequisites

* fix(desktop): align nested state selections with aliases

* fix(desktop): check build runtime export capability

* fix(desktop): provide complete runtime repack command

* fix(desktop): retain runtime probe failures

* test(desktop): identify capture independently of schema preflight

* fix(desktop): preserve document URLs and value formats

* fix(desktop): bound added checks and omit noisy text guards

* fix(desktop): exclude unseeded locks from task checks

* fix(desktop): preserve draft bounds and launch URLs

* fix(desktop): render draft values using their source format

* fix(desktop): preserve launch URLs and JSON draft values

* fix(desktop): recognize captured file URL documents

* fix(desktop): render captured file URLs for runtime home

* fix(desktop): distinguish phone numbers from save metadata

* fix(desktop): preserve launch URLs and user text

* fix(desktop): preserve captured URLs and user text

* fix(desktop): preserve local file URL authority

* fix(desktop): preserve local file URL authority

* fix(desktop): preserve local file URL authority

* fix(desktop): render captured file URLs at launch

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): retain context for generated draft values

* fix(desktop): retain context for generated draft values

* fix(desktop): retain context for generated draft values

* test(desktop): cover generated IDs in text guards

* test(desktop): cover generated IDs in text guards

* test(desktop): cover generated IDs in text guards

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): retain clean text in noisy record fields

* fix(desktop): classify added line values in one pass

* fix(desktop): apply XML quote rules to text drafts

* fix(desktop): distinguish XML attributes from quoted text

* fix(desktop): preserve parsed XML line context

* Format appTaskChecks.ts with the pinned oxfmt

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(desktop): retain partial XML syntax facts

* fix(desktop): recognize markdown autolinks in drafts

* fix(desktop): reuse export exclusions in task drafts

* fix(desktop): report unchecked client build paths

* docs(desktop): clarify gzip scrub limits

* fix(desktop): reuse export exclusions in task drafts

* docs(desktop): clarify gzip scrub limits

* fix(setup): own desktop build process cleanup

* fix(doctor): compare desktop settings with resolved defaults

* style(desktop): format the noisy-record draft files with the pinned oxfmt

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* test(desktop): give the root-array draft test its own describe

The records describe grew past the 150-line lint limit with it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(doctor): inspect client-recorded desktop runners

* fix(doctor): reuse matching runner probes

* fix(setup): propagate cancellation to desktop actions

* fix(setup): stop Hopper on cancel, never report a cancelled setup ready, and keep a failed action's client setting

- The Hopper install gets setup's signal: Linux already honoured it, and the
  macOS installer now stops its downloads and stops before mounting or copying.
- runSetup checks the signal after the final doctor and close, so a
  cancellation there raises instead of returning ready.
- A failed pack or agentenv install no longer writes its archive or runner to
  client configs, so the setting the client already had stays.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(setup): keep the completed setup result in a cancellation after cleanup

A cancellation during the final doctor or host close carried only the applied
actions, dropping each client's result and backup path and the doctor report.
It now carries the whole result as setup_result, as doctor's cancellation
carries its report.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* test(desktop): move launch execution to boundary suite

* fix(desktop): redact build schema failure output

* refactor(desktop): normalize schema failure once

* fix(desktop): omit unsafe schema parser snippets

* fix(desktop): preserve draft change and selected path evidence

* test(desktop): group retained dconf note regressions

* fix(desktop): respect archive entry format in draft checks

* test(desktop): separate unowned-file draft note cases

* fix(desktop): preserve explicitly selected journal documents

* fix(xml): avoid scanning selected ancestors per tag

* fix(desktop): exclude covered text runs from draft counts

* fix: preserve text when drafting desktop checks

* fix: restore nested desktop state aliases

* refactor: share UUID recognition across draft checks

* fix: retain multiline XML attribute context

* fix: retain relationship identifiers in task drafts

* docs: clarify desktop draft identifier handling

* test(desktop): type formatting run cases as pairs

* fix(desktop): carry document format into selector evaluation

* test(desktop): separate markup boundary regression group

* fix(desktop): propagate formats through draft selectors

* fix(desktop): switch selector format within archive entries

* test(desktop): remove duplicate seed filename case

* fix(setup): retain diagnostics when cancellation overlaps failure

* refactor(setup): keep command cancellation at its owner

* test(setup): verify cancellation at the application boundary

* test(desktop): pass JSON format in exported index parity

* docs(desktop): clarify task checks before scratch export

* fix(desktop): respell selected paths in file URLs

* test(desktop): group captured document spelling cases

* fix(desktop): bound draft preview serialization

* fix(desktop): restore selected state aliases

* fix(desktop): respect entry format in draft noise

* test(desktop): match exported alias evidence at its JSON boundary

* fix(desktop): retain app state logs in exported seeds

* fix: align desktop numeric seed comparisons

* test(desktop): keep one draft exclusion fixture import

* test(desktop): retain log eligibility across draft test groups

* fix(doctor): resolve empty registered desktop runner

* style: fix desktop launch test formatting

* style: format native command path schema

* fix(desktop): map selected external launch paths

* style(desktop): format seed document regressions

* test(desktop): group launch URL regressions

* fix(desktop): omit redundant nested state aliases

* fix(desktop): compare added free text as a whole

* fix(desktop): check recompressed seeds as shipped

* docs(desktop): clarify recovered seed format

* test(desktop): group shipped gzip seed checks

* fix: retain quoted identifier text in task drafts

* fix: recognize Unicode XML in desktop state readers

* fix(desktop): bound nested draft checks

* fix(desktop): explain missing arrays in truncated views

* fix(desktop): find XML type references in archives

* test(desktop): remove duplicated capture assertions

* fix(desktop): retain nested omitted text boundaries

* style(desktop): format draft value imports

* test(desktop): group model and draft value checks

* fix(desktop): map captured launch paths once

* refactor: remove unused whole-text guard state

* refactor: stop passing unused text children

* test: align free-text checks with whole-note policy

* fix: validate recompressed desktop archive seeds

* style(desktop): format archive seed regression

* fix(desktop): retain placed-item sibling guards

* fix(desktop): preserve archive paths and bound doctor reads

* fix(doctor): refuse non-files before descriptor admission

* fix(setup): track remaining cleanup resources across retries

* test(desktop): specify XML format in heap pairing fixture

* fix(doctor): query agentenv for model endpoint

* fix(doctor): preserve uncertainty for empty endpoint override

* fix(desktop): redact runtime schema errors

* fix(desktop): normalize captured file URLs

* fix(desktop): report seeded files by capture path

* fix(desktop): retain startup readiness failure stage

* fix(desktop): retain JSON date checks

* fix(desktop): preserve archive formatting checks

* fix(desktop): preserve explicitly selected journal files

* fix(desktop): report build command transport limits

* docs(desktop): clarify unreadable dconf versions

* test(desktop): remove duplicate history regression

* fix(desktop): align XML names with exported reader

* fix(desktop): create selected state alias targets

* fix(desktop): inspect supported runtime archives

* fix(desktop): retain record identity in draft checks

* fix(desktop): scrub XML independently of reader compatibility

* fix(desktop): preserve file aliases and reader diagnostics

* style(desktop): format review fixes

* style(desktop): format capture review fixes

---------

Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: morluto <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-09 23:02:31 +08:00
61ab3f0c4f feat(desktop): name a record by a nested field or a child's attribute (#9185)
* fix(desktop): keep a selected folder that is named like a database log

A folder the caller selected stays a selected root when its name ends in
-journal or -wal. A generated log beside a database file still does not.

* fix(desktop): refuse a build command that exceeds the argument vector

Splitting one argument still leaves the whole command under Linux's E2BIG
limit. A request past that budget is refused before the process starts.

* fix(desktop): remap a captured path in an env assignment

The program word stays the program. A NAME=value assignment keeps its name
and follows a captured path value when that path's spelling moves.

* fix(desktop): keep oversized text out of draft guards

A value or line longer than the draft's text bound is not copied into a
guard, so one large frame cannot fill the task by itself.

* docs(desktop): correct dconf and check-preview guidance

A dconf version kept without its bytes is unreadable, not an empty key
list. A values preview is copied into a check only when it is an uncut scalar.

* fix(desktop): keep an empty env value empty

An empty assignment is not a path. Resolving it named the working directory
and rewrote the value when that directory's spelling moved.

* fix(desktop): keep a run's font on the run, not the frame's text

A formatting attribute such as Scribus FONT is not the document's words.
Joining it across runs made a frame-wide text check of ItalicBold that
failed when a run was split. The font stays a value check on its own run.

* fix(desktop): do not pair JSON records by a selector-shaped field

A field named @record_id matched the id suffix and became [@record_id=one],
which reads an XML attribute. Records paired while their pointers matched
nothing. Names that start with @ or > are not id fields.

* fix(desktop): count a save-numbered id once when pairing members

xml:id and draw:id values such as id123456 were both generated and
numbered, so the same selector was counted twice and refused. A text
edit of two elements keyed only by those ids now keeps its check.

* fix(desktop): count members of root JSON arrays

* fix(desktop): preserve selected state directory aliases

* docs(desktop): explain tool and skill refresh prerequisites

* fix(desktop): align nested state selections with aliases

* fix(desktop): check build runtime export capability

* fix(desktop): provide complete runtime repack command

* fix(desktop): retain runtime probe failures

* test(desktop): identify capture independently of schema preflight

* fix(desktop): preserve document URLs and value formats

* fix(desktop): bound added checks and omit noisy text guards

* fix(desktop): exclude unseeded locks from task checks

* fix(desktop): preserve draft bounds and launch URLs

* fix(desktop): render draft values using their source format

* fix(desktop): preserve launch URLs and JSON draft values

* fix(desktop): recognize captured file URL documents

* fix(desktop): render captured file URLs for runtime home

* fix(desktop): distinguish phone numbers from save metadata

* fix(desktop): preserve launch URLs and user text

* fix(desktop): preserve captured URLs and user text

* fix(desktop): preserve local file URL authority

* fix(desktop): preserve local file URL authority

* fix(desktop): preserve local file URL authority

* fix(desktop): render captured file URLs at launch

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): retain context for generated draft values

* fix(desktop): retain context for generated draft values

* fix(desktop): retain context for generated draft values

* test(desktop): cover generated IDs in text guards

* test(desktop): cover generated IDs in text guards

* test(desktop): cover generated IDs in text guards

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): retain clean text in noisy record fields

* fix(desktop): classify added line values in one pass

* fix(desktop): apply XML quote rules to text drafts

* fix(desktop): distinguish XML attributes from quoted text

* fix(desktop): preserve parsed XML line context

* Format appTaskChecks.ts with the pinned oxfmt

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(desktop): retain partial XML syntax facts

* fix(desktop): recognize markdown autolinks in drafts

* fix(desktop): reuse export exclusions in task drafts

* docs(desktop): clarify gzip scrub limits

* style(desktop): format the noisy-record draft files with the pinned oxfmt

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* test(desktop): give the root-array draft test its own describe

The records describe grew past the 150-line lint limit with it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* test(desktop): move launch execution to boundary suite

* fix(desktop): redact build schema failure output

* refactor(desktop): normalize schema failure once

* fix(desktop): omit unsafe schema parser snippets

* fix(desktop): preserve draft change and selected path evidence

* test(desktop): group retained dconf note regressions

* fix(desktop): respect archive entry format in draft checks

* test(desktop): separate unowned-file draft note cases

* fix(desktop): preserve explicitly selected journal documents

* fix(xml): avoid scanning selected ancestors per tag

* fix(desktop): exclude covered text runs from draft counts

* fix: preserve text when drafting desktop checks

* fix: restore nested desktop state aliases

* refactor: share UUID recognition across draft checks

* fix: retain multiline XML attribute context

* fix: retain relationship identifiers in task drafts

* docs: clarify desktop draft identifier handling

* test(desktop): type formatting run cases as pairs

* fix(desktop): carry document format into selector evaluation

* test(desktop): separate markup boundary regression group

* fix(desktop): propagate formats through draft selectors

* fix(desktop): switch selector format within archive entries

* test(desktop): remove duplicate seed filename case

* test(desktop): pass JSON format in exported index parity

* docs(desktop): clarify task checks before scratch export

* fix(desktop): respell selected paths in file URLs

* test(desktop): group captured document spelling cases

* fix(desktop): bound draft preview serialization

* fix(desktop): restore selected state aliases

* fix(desktop): respect entry format in draft noise

* test(desktop): match exported alias evidence at its JSON boundary

* fix(desktop): retain app state logs in exported seeds

* fix: align desktop numeric seed comparisons

* test(desktop): keep one draft exclusion fixture import

* test(desktop): retain log eligibility across draft test groups

* style: fix desktop launch test formatting

* style: format native command path schema

* fix(desktop): map selected external launch paths

* style(desktop): format seed document regressions

* test(desktop): group launch URL regressions

* fix(desktop): omit redundant nested state aliases

* fix(desktop): compare added free text as a whole

* fix(desktop): check recompressed seeds as shipped

* docs(desktop): clarify recovered seed format

* test(desktop): group shipped gzip seed checks

* fix: retain quoted identifier text in task drafts

* fix: recognize Unicode XML in desktop state readers

* fix(desktop): bound nested draft checks

* fix(desktop): explain missing arrays in truncated views

* fix(desktop): find XML type references in archives

* test(desktop): remove duplicated capture assertions

* fix(desktop): retain nested omitted text boundaries

* style(desktop): format draft value imports

* test(desktop): group model and draft value checks

* fix(desktop): map captured launch paths once

* refactor: remove unused whole-text guard state

* refactor: stop passing unused text children

* test: align free-text checks with whole-note policy

* fix: validate recompressed desktop archive seeds

* style(desktop): format archive seed regression

* fix(desktop): retain placed-item sibling guards

* test(desktop): specify XML format in heap pairing fixture

* fix(desktop): redact runtime schema errors

* fix(desktop): normalize captured file URLs

* fix(desktop): report seeded files by capture path

* fix(desktop): retain startup readiness failure stage

* fix(desktop): retain JSON date checks

* fix(desktop): preserve archive formatting checks

* fix(desktop): preserve explicitly selected journal files

* fix(desktop): report build command transport limits

* docs(desktop): clarify unreadable dconf versions

* test(desktop): remove duplicate history regression

* fix(desktop): align XML names with exported reader

* fix(desktop): retain record identity in draft checks

* fix(desktop): scrub XML independently of reader compatibility

* style(desktop): format review fixes

* style(desktop): format capture review fixes

---------

Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: morluto <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-09 23:01:22 +08:00
fd39977c32 docs(desktop): set up a desktop build host from a fresh Linux machine (#9184)
* fix(desktop): keep a program word and a directory's neighbor

The program after env stays the program even when a captured file sits in a
folder of that name. A selected directory is not a database, so a neighboring
file keeps the parent folder's spelling.

* fix(desktop): record whether a selected path is a directory

Capture stores the walked path's kind. A neighboring file of a selected
directory keeps the parent folder's spelling even when that directory never
changes and its children are not content roots.

* fix(desktop): mark containing paths without a pairwise scan

A recorded path marks its known ancestors as directories in one walk up
the path, instead of comparing every recorded path with every other.

* fix(desktop): keep a selected folder that is named like a database log

A folder the caller selected stays a selected root when its name ends in
-journal or -wal. A generated log beside a database file still does not.

* fix(desktop): refuse a build command that exceeds the argument vector

Splitting one argument still leaves the whole command under Linux's E2BIG
limit. A request past that budget is refused before the process starts.

* fix(desktop): remap a captured path in an env assignment

The program word stays the program. A NAME=value assignment keeps its name
and follows a captured path value when that path's spelling moves.

* fix(desktop): keep oversized text out of draft guards

A value or line longer than the draft's text bound is not copied into a
guard, so one large frame cannot fill the task by itself.

* docs(desktop): correct dconf and check-preview guidance

A dconf version kept without its bytes is unreadable, not an empty key
list. A values preview is copied into a check only when it is an uncut scalar.

* fix(desktop): keep an empty env value empty

An empty assignment is not a path. Resolving it named the working directory
and rewrote the value when that directory's spelling moved.

* fix(desktop): keep a run's font on the run, not the frame's text

A formatting attribute such as Scribus FONT is not the document's words.
Joining it across runs made a frame-wide text check of ItalicBold that
failed when a run was split. The font stays a value check on its own run.

* fix(desktop): do not pair JSON records by a selector-shaped field

A field named @record_id matched the id suffix and became [@record_id=one],
which reads an XML attribute. Records paired while their pointers matched
nothing. Names that start with @ or > are not id fields.

* fix(desktop): count a save-numbered id once when pairing members

xml:id and draw:id values such as id123456 were both generated and
numbered, so the same selector was counted twice and refused. A text
edit of two elements keyed only by those ids now keeps its check.

* fix(desktop): preserve selected state directory aliases

* docs(desktop): explain tool and skill refresh prerequisites

* fix(desktop): align nested state selections with aliases

* fix(desktop): check build runtime export capability

* fix(desktop): provide complete runtime repack command

* fix(desktop): retain runtime probe failures

* test(desktop): identify capture independently of schema preflight

* fix(desktop): preserve document URLs and value formats

* fix(desktop): bound added checks and omit noisy text guards

* fix(desktop): exclude unseeded locks from task checks

* fix(desktop): preserve draft bounds and launch URLs

* fix(desktop): render draft values using their source format

* fix(desktop): preserve launch URLs and JSON draft values

* fix(desktop): recognize captured file URL documents

* fix(desktop): render captured file URLs for runtime home

* fix(desktop): distinguish phone numbers from save metadata

* fix(desktop): preserve launch URLs and user text

* fix(desktop): preserve captured URLs and user text

* fix(desktop): preserve local file URL authority

* fix(desktop): preserve local file URL authority

* fix(desktop): preserve local file URL authority

* fix(desktop): render captured file URLs at launch

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): retain context for generated draft values

* fix(desktop): retain context for generated draft values

* fix(desktop): retain context for generated draft values

* test(desktop): cover generated IDs in text guards

* test(desktop): cover generated IDs in text guards

* test(desktop): cover generated IDs in text guards

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): retain clean text in noisy record fields

* fix(desktop): classify added line values in one pass

* fix(desktop): apply XML quote rules to text drafts

* fix(desktop): distinguish XML attributes from quoted text

* fix(desktop): preserve parsed XML line context

* fix(desktop): retain partial XML syntax facts

* fix(desktop): recognize markdown autolinks in drafts

* fix(desktop): reuse export exclusions in task drafts

* docs(desktop): clarify gzip scrub limits

* style(desktop): format the noisy-record draft files with the pinned oxfmt

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* test(desktop): move launch execution to boundary suite

* fix(desktop): redact build schema failure output

* refactor(desktop): normalize schema failure once

* fix(desktop): omit unsafe schema parser snippets

* fix(desktop): preserve draft change and selected path evidence

* test(desktop): group retained dconf note regressions

* fix(desktop): respect archive entry format in draft checks

* test(desktop): separate unowned-file draft note cases

* fix(desktop): preserve explicitly selected journal documents

* fix(xml): avoid scanning selected ancestors per tag

* fix(desktop): exclude covered text runs from draft counts

* fix: preserve text when drafting desktop checks

* fix: restore nested desktop state aliases

* refactor: share UUID recognition across draft checks

* fix: retain multiline XML attribute context

* fix: retain relationship identifiers in task drafts

* docs: clarify desktop draft identifier handling

* test(desktop): type formatting run cases as pairs

* test(desktop): separate markup boundary regression group

* test(desktop): remove duplicate seed filename case

* docs(desktop): clarify task checks before scratch export

* fix(desktop): respell selected paths in file URLs

* test(desktop): group captured document spelling cases

* fix(desktop): bound draft preview serialization

* fix(desktop): restore selected state aliases

* fix(desktop): respect entry format in draft noise

* test(desktop): match exported alias evidence at its JSON boundary

* fix(desktop): retain app state logs in exported seeds

* fix: align desktop numeric seed comparisons

* test(desktop): keep one draft exclusion fixture import

* test(desktop): retain log eligibility across draft test groups

* style: fix desktop launch test formatting

* style: format native command path schema

* fix(desktop): map selected external launch paths

* style(desktop): format seed document regressions

* test(desktop): group launch URL regressions

* fix(desktop): omit redundant nested state aliases

* fix(desktop): compare added free text as a whole

* fix(desktop): check recompressed seeds as shipped

* docs(desktop): clarify recovered seed format

* test(desktop): group shipped gzip seed checks

* fix: retain quoted identifier text in task drafts

* fix: recognize Unicode XML in desktop state readers

* fix(desktop): bound nested draft checks

* fix(desktop): explain missing arrays in truncated views

* fix(desktop): find XML type references in archives

* test(desktop): remove duplicated capture assertions

* fix(desktop): retain nested omitted text boundaries

* style(desktop): format draft value imports

* test(desktop): group model and draft value checks

* fix(desktop): map captured launch paths once

* refactor: remove unused whole-text guard state

* refactor: stop passing unused text children

* test: align free-text checks with whole-note policy

* fix: validate recompressed desktop archive seeds

* style(desktop): format archive seed regression

* fix(desktop): retain placed-item sibling guards

* fix(desktop): redact runtime schema errors

* fix(desktop): normalize captured file URLs

* fix(desktop): report seeded files by capture path

* fix(desktop): retain startup readiness failure stage

* fix(desktop): retain JSON date checks

* fix(desktop): preserve archive formatting checks

* fix(desktop): preserve explicitly selected journal files

* fix(desktop): report build command transport limits

* docs(desktop): clarify unreadable dconf versions

* test(desktop): remove duplicate history regression

* fix(desktop): align XML names with exported reader

* fix(desktop): scrub XML independently of reader compatibility

* style(desktop): format review fixes

* style(desktop): format capture review fixes

---------

Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: morluto <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-09 22:59:45 +08:00
012861ce1d feat(desktop): draft child-text selectors, member counts and attribute text, and fold in a third batch's findings (#9132)
* fix(desktop): follow a database mapping and own limitation text

A selected database keeps its log when a parent folder moves or the file
sits outside the home. Trash and seed-lock tests compare the owning notice
with the paths, and launch options that are not captured paths stay as written.

* test(desktop): pass the selected log into the draft

The export's selected home paths decide which log stays in the draft.
The line-guard test now names that log instead of relying on its reason.

* fix(desktop): retarget a settings folder that holds captured files

A nested profile directory is a captured path when a seeded file is inside
it. An option value that only resolves under the home stays as written.

* fix(desktop): keep a program word and a directory's neighbor

The program after env stays the program even when a captured file sits in a
folder of that name. A selected directory is not a database, so a neighboring
file keeps the parent folder's spelling.

* fix(desktop): record whether a selected path is a directory

Capture stores the walked path's kind. A neighboring file of a selected
directory keeps the parent folder's spelling even when that directory never
changes and its children are not content roots.

* fix(desktop): mark containing paths without a pairwise scan

A recorded path marks its known ancestors as directories in one walk up
the path, instead of comparing every recorded path with every other.

* fix(desktop): keep a selected folder that is named like a database log

A folder the caller selected stays a selected root when its name ends in
-journal or -wal. A generated log beside a database file still does not.

* fix(desktop): refuse a build command that exceeds the argument vector

Splitting one argument still leaves the whole command under Linux's E2BIG
limit. A request past that budget is refused before the process starts.

* fix(desktop): remap a captured path in an env assignment

The program word stays the program. A NAME=value assignment keeps its name
and follows a captured path value when that path's spelling moves.

* fix(desktop): keep oversized text out of draft guards

A value or line longer than the draft's text bound is not copied into a
guard, so one large frame cannot fill the task by itself.

* docs(desktop): correct dconf and check-preview guidance

A dconf version kept without its bytes is unreadable, not an empty key
list. A values preview is copied into a check only when it is an uncut scalar.

* fix(desktop): keep an empty env value empty

An empty assignment is not a path. Resolving it named the working directory
and rewrote the value when that directory's spelling moved.

* fix(desktop): keep a run's font on the run, not the frame's text

A formatting attribute such as Scribus FONT is not the document's words.
Joining it across runs made a frame-wide text check of ItalicBold that
failed when a run was split. The font stays a value check on its own run.

* fix(desktop): do not pair JSON records by a selector-shaped field

A field named @record_id matched the id suffix and became [@record_id=one],
which reads an XML attribute. Records paired while their pointers matched
nothing. Names that start with @ or > are not id fields.

* fix(desktop): count a save-numbered id once when pairing members

xml:id and draw:id values such as id123456 were both generated and
numbered, so the same selector was counted twice and refused. A text
edit of two elements keyed only by those ids now keeps its check.

* fix(desktop): preserve selected state directory aliases

* fix(desktop): align nested state selections with aliases

* fix(desktop): check build runtime export capability

* fix(desktop): provide complete runtime repack command

* fix(desktop): retain runtime probe failures

* test(desktop): identify capture independently of schema preflight

* fix(desktop): preserve document URLs and value formats

* fix(desktop): bound added checks and omit noisy text guards

* fix(desktop): exclude unseeded locks from task checks

* fix(desktop): preserve draft bounds and launch URLs

* fix(desktop): render draft values using their source format

* fix(desktop): preserve launch URLs and JSON draft values

* fix(desktop): recognize captured file URL documents

* fix(desktop): render captured file URLs for runtime home

* fix(desktop): distinguish phone numbers from save metadata

* fix(desktop): preserve launch URLs and user text

* fix(desktop): preserve captured URLs and user text

* fix(desktop): preserve local file URL authority

* fix(desktop): preserve local file URL authority

* fix(desktop): preserve local file URL authority

* fix(desktop): render captured file URLs at launch

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): retain context for generated draft values

* fix(desktop): retain context for generated draft values

* fix(desktop): retain context for generated draft values

* test(desktop): cover generated IDs in text guards

* test(desktop): cover generated IDs in text guards

* test(desktop): cover generated IDs in text guards

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): retain clean text in noisy record fields

* fix(desktop): classify added line values in one pass

* fix(desktop): apply XML quote rules to text drafts

* fix(desktop): distinguish XML attributes from quoted text

* fix(desktop): preserve parsed XML line context

* fix(desktop): retain partial XML syntax facts

* fix(desktop): recognize markdown autolinks in drafts

* fix(desktop): reuse export exclusions in task drafts

* docs(desktop): clarify gzip scrub limits

* style(desktop): format the noisy-record draft files with the pinned oxfmt

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* test(desktop): move launch execution to boundary suite

* fix(desktop): redact build schema failure output

* refactor(desktop): normalize schema failure once

* fix(desktop): omit unsafe schema parser snippets

* fix(desktop): preserve draft change and selected path evidence

* test(desktop): group retained dconf note regressions

* fix(desktop): respect archive entry format in draft checks

* test(desktop): separate unowned-file draft note cases

* fix(desktop): preserve explicitly selected journal documents

* fix(xml): avoid scanning selected ancestors per tag

* fix(desktop): exclude covered text runs from draft counts

* fix: preserve text when drafting desktop checks

* fix: restore nested desktop state aliases

* refactor: share UUID recognition across draft checks

* fix: retain multiline XML attribute context

* fix: retain relationship identifiers in task drafts

* docs: clarify desktop draft identifier handling

* test(desktop): type formatting run cases as pairs

* test(desktop): separate markup boundary regression group

* docs(desktop): clarify task checks before scratch export

* fix(desktop): respell selected paths in file URLs

* test(desktop): group captured document spelling cases

* fix(desktop): bound draft preview serialization

* fix(desktop): restore selected state aliases

* fix(desktop): respect entry format in draft noise

* test(desktop): match exported alias evidence at its JSON boundary

* fix(desktop): retain app state logs in exported seeds

* fix: align desktop numeric seed comparisons

* test(desktop): keep one draft exclusion fixture import

* test(desktop): retain log eligibility across draft test groups

* style: fix desktop launch test formatting

* style: format native command path schema

* fix(desktop): map selected external launch paths

* style(desktop): format seed document regressions

* test(desktop): group launch URL regressions

* fix(desktop): omit redundant nested state aliases

* fix(desktop): compare added free text as a whole

* fix(desktop): check recompressed seeds as shipped

* docs(desktop): clarify recovered seed format

* test(desktop): group shipped gzip seed checks

* fix: retain quoted identifier text in task drafts

* fix: recognize Unicode XML in desktop state readers

* fix(desktop): bound nested draft checks

* fix(desktop): explain missing arrays in truncated views

* fix(desktop): find XML type references in archives

* test(desktop): remove duplicated capture assertions

* fix(desktop): retain nested omitted text boundaries

* style(desktop): format draft value imports

* test(desktop): group model and draft value checks

* fix(desktop): map captured launch paths once

* refactor: remove unused whole-text guard state

* refactor: stop passing unused text children

* test: align free-text checks with whole-note policy

* fix: validate recompressed desktop archive seeds

* style(desktop): format archive seed regression

* fix(desktop): retain placed-item sibling guards

* fix(desktop): redact runtime schema errors

* fix(desktop): normalize captured file URLs

* fix(desktop): report seeded files by capture path

* fix(desktop): retain startup readiness failure stage

* fix(desktop): retain JSON date checks

* fix(desktop): preserve archive formatting checks

* fix(desktop): preserve explicitly selected journal files

* fix(desktop): report build command transport limits

* docs(desktop): clarify unreadable dconf versions

* style(desktop): format capture review fixes

---------

Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: morluto <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-09 22:56:44 +08:00
0dcd0dfc20 feat(desktop): check text kept in attributes, name a record by a child's text, and count members (#9114)
* fix(desktop): keep a lone lock a document and drop one beside its file

A selected name such as notes.lck stays a document, so launch and the draft
still treat it as the caller's file. A lock beside a recorded sibling is left
out of the seed unless that lock path itself was selected.

* fix(desktop): require the added record and leave save times out of list checks

A record a selector names is checked itself, so its words have to be in that
record. When an unnamed record only repeats words the seed already has, a
list that holds a save time is checked by the text around that time. A later
save of the same records still passes, and a missing or rewritten record fails.

* fix(desktop): judge the older index helper by pointer segments only

A leading zero in a file name or a URL does not change how the older index
helper reads a pointer. The witness still rejects that helper when a pointer
segment is a number such as 01.

* fix(desktop): keep a document whose name ends in .lock

A lock beside a recorded file still stays out of the seed unless that lock
was selected. A document such as Cargo.lock in the home is the user's file,
so the seed keeps it. An application lock in the home, such as poedit.lock,
stays out.

* fix(desktop): do not suggest list text the seed already passes

A repeated record is shown by text the seed does not hold. The seed's own
text is not a check. A pointer inside a check value is not a pointer segment
for the older index helper.

* fix(desktop): do not let a left-out lock hide settings checks

A sibling lock the seed omits is not the document the draft follows. Settings
changes stay suggested. The unused sibling-lock name helper is removed.

* fix(desktop): keep a linked settings file in the folder the link points at

A selected ~/.config alias no longer moves MuseScore settings to that alias.
The seed keeps settings/MuseScore or Documents, which is the path the export
opens the note from.

* fix(desktop): split home fetches by answer size and keep a size refusal

A batch of tiny files stops before each path's envelope exceeds the host
answer budget. A capture output past that ceiling stays a resource error
instead of becoming a generic exit.

* fix(desktop): seed a selected link under the path the app uses

The selected spelling wins, so ~/.config/MuseScore is not rewritten to the
folder it points at and the note stays the one launched document. A database
wal and journal follow that database. A launch argument is respelled the same
way. Teardown signals a detached PID only when its start identity still matches.

* fix(desktop): keep a witness's actions and an incomplete checkpoint

A failed witness save retries the action log it first recorded. A deletion
left unconfirmed between the seed and the end is not reported as no change.
Windows packs npm through a shell, which can start npm.cmd.

* fix(desktop): read verifier pointers from the parsed checks

A brace inside a check value is not an object boundary. A leading-zero
pointer after that value still rejects the older index helper.

* fix(desktop): leave out a sibling lock under a selected folder

A file under a selected folder inherits selected_path. That does not make
the lock beside its map a chosen document, so a settings change stays drafted.

* fix(desktop): prefer the most specific home spelling and retarget launch files

A selected parent directory no longer hides a settings folder walked through
a link. A launch filename under that folder is replaced with the seeded
file's absolute path.

* fix(desktop): pack the build runtime through npm's JavaScript entry

npm pack and npm ci no longer spawn npm.cmd through a shell, so a temporary
directory whose path contains spaces stays one argument.

* fix(desktop): spell launch settings and keep a database log exact

A database log matches only that file, so a neighboring folder is not moved.
A launch option and the working directory use the same home spelling as the seed.

* fix(desktop): draft a lock the export selected exactly

The draft uses the same selected paths as the export. A lock chosen by
itself stays in the draft. A lock under a selected folder stays out.

* fix(desktop): move a state database's logs with the database

The write-ahead log and journal follow the spelling the database received,
including a walked state link. A neighboring folder stays put. A separate
--config argument uses that spelling too.

* fix(desktop): keep a selected file ahead of a database-log guess

A file selected as itself keeps that spelling even when its name ends in
-journal. Relative launch arguments are resolved in the captured working
directory before that directory moves.

* fix(desktop): keep outside-home database logs and option values

A selected database outside the home keeps its write-ahead log. Launch
options are rewritten only when they name a captured file or settings path.

* fix(desktop): follow a database mapping and own limitation text

A selected database keeps its log when a parent folder moves or the file
sits outside the home. Trash and seed-lock tests compare the owning notice
with the paths, and launch options that are not captured paths stay as written.

* fix(desktop): retarget a settings folder that holds captured files

A nested profile directory is a captured path when a seeded file is inside
it. An option value that only resolves under the home stays as written.

* fix(desktop): keep a program word and a directory's neighbor

The program after env stays the program even when a captured file sits in a
folder of that name. A selected directory is not a database, so a neighboring
file keeps the parent folder's spelling.

* fix(desktop): record whether a selected path is a directory

Capture stores the walked path's kind. A neighboring file of a selected
directory keeps the parent folder's spelling even when that directory never
changes and its children are not content roots.

* fix(desktop): mark containing paths without a pairwise scan

A recorded path marks its known ancestors as directories in one walk up
the path, instead of comparing every recorded path with every other.

* fix(desktop): keep a selected folder that is named like a database log

A folder the caller selected stays a selected root when its name ends in
-journal or -wal. A generated log beside a database file still does not.

* fix(desktop): refuse a build command that exceeds the argument vector

Splitting one argument still leaves the whole command under Linux's E2BIG
limit. A request past that budget is refused before the process starts.

* fix(desktop): remap a captured path in an env assignment

The program word stays the program. A NAME=value assignment keeps its name
and follows a captured path value when that path's spelling moves.

* fix(desktop): keep oversized text out of draft guards

A value or line longer than the draft's text bound is not copied into a
guard, so one large frame cannot fill the task by itself.

* docs(desktop): correct dconf and check-preview guidance

A dconf version kept without its bytes is unreadable, not an empty key
list. A values preview is copied into a check only when it is an uncut scalar.

* fix(desktop): keep an empty env value empty

An empty assignment is not a path. Resolving it named the working directory
and rewrote the value when that directory's spelling moved.

* fix(desktop): check build runtime export capability

* fix(desktop): provide complete runtime repack command

* fix(desktop): retain runtime probe failures

* test(desktop): identify capture independently of schema preflight

* fix(desktop): preserve document URLs and value formats

* fix(desktop): bound added checks and omit noisy text guards

* fix(desktop): preserve launch URLs and JSON draft values

* fix(desktop): recognize captured file URL documents

* fix(desktop): render captured file URLs for runtime home

* fix(desktop): distinguish phone numbers from save metadata

* fix(desktop): preserve launch URLs and user text

* fix(desktop): preserve local file URL authority

* fix(desktop): preserve local file URL authority

* fix(desktop): render captured file URLs at launch

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): retain context for generated draft values

* fix(desktop): retain context for generated draft values

* test(desktop): cover generated IDs in text guards

* test(desktop): cover generated IDs in text guards

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): retain clean text in noisy record fields

* style(desktop): format the noisy-record draft files with the pinned oxfmt

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* test(desktop): move launch execution to boundary suite

* fix(desktop): redact build schema failure output

* refactor(desktop): normalize schema failure once

* fix(desktop): omit unsafe schema parser snippets

* fix(desktop): preserve draft change and selected path evidence

* test(desktop): group retained dconf note regressions

* fix(desktop): respect archive entry format in draft checks

* test(desktop): separate unowned-file draft note cases

* fix(desktop): preserve explicitly selected journal documents

* fix(xml): avoid scanning selected ancestors per tag

* docs(desktop): clarify task checks before scratch export

* fix(desktop): respell selected paths in file URLs

* test(desktop): group captured document spelling cases

* fix(desktop): bound draft preview serialization

* fix(desktop): restore selected state aliases

* fix(desktop): respect entry format in draft noise

* test(desktop): match exported alias evidence at its JSON boundary

* fix(desktop): retain app state logs in exported seeds

* style: fix desktop launch test formatting

* style: format native command path schema

* fix(desktop): map selected external launch paths

* style(desktop): format seed document regressions

* test(desktop): group launch URL regressions

* fix(desktop): omit redundant nested state aliases

* fix(desktop): compare added free text as a whole

* fix(desktop): check recompressed seeds as shipped

* docs(desktop): clarify recovered seed format

* test(desktop): group shipped gzip seed checks

* fix(desktop): map captured launch paths once

* refactor: remove unused whole-text guard state

* refactor: stop passing unused text children

* test: align free-text checks with whole-note policy

* fix: validate recompressed desktop archive seeds

* style(desktop): format archive seed regression

* fix(desktop): redact runtime schema errors

* fix(desktop): normalize captured file URLs

* fix(desktop): report seeded files by capture path

* fix(desktop): retain startup readiness failure stage

* fix(desktop): retain JSON date checks

* fix(desktop): preserve archive formatting checks

* fix(desktop): preserve explicitly selected journal files

* fix(desktop): report build command transport limits

* docs(desktop): clarify unreadable dconf versions

* style(desktop): format capture review fixes

---------

Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: morluto <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-09 22:53:18 +08:00
35f1c3517f feat(desktop): install extra packages beside an archive app, and keep a package file's dependencies at export (#9112)
* fix(desktop): keep added-record checks off ids, dates, and joined timestamps

A position-named record's fields keep their paths, so an identifier, a stamped date, and text past the limit are not suggested checks. A whole-text check does not climb into an ancestor whose text joins a timestamp.

* fix(desktop): bound home fetches and keep unsettled edits readable

Split home-folder reads by the guest answer budget, keep a capacity error
from the capture output, and drop the superseded task-argument refusal.
Grade kept text per line, leave unretained dconf unread, and reserve
by-position notes for XML children. Map a linked database's sidecars
through the selected spelling and stop a detached capture only when its
start identity still owns the pid.

* fix(desktop): describe unretained dconf as unread

The key comparison treats a missing copy as unknown. The comment still
said that copy counted as an empty key list.

* test(desktop): keep a capture capacity error through endedCapture

An output past the guest answer ceiling stays the resource constraint,
with its heap recovery and non-retryable status, instead of a generic
capture-exit message.

* fix(desktop): keep nested save times and formatting runs out of checks

A field check drops save-time leaves before it joins the field, so a nested
timestamp is not part of the suggested text. A text check beside a save time
uses the paragraph when the diff names a formatting run.

* test(desktop): read paragraph pointers from checks that have them

* test(desktop): expect a large task to export intact

The 96 KiB refusal is gone. A prompt past that size reaches the computer
and comes back unchanged, instead of failing before export.

* fix(desktop): keep real edits that save-side heuristics were dropping

Repeated unnamed fields stay content checks. A formula that still has
text is not renumbered with its ExprID. One gained style attribute is
the edit; a repeated fill-in stays upkeep. Phone numbers and plain
clock times stay text, and a decimal is the element's whole text. An
older verifier matches on the task it states, not its evaluator source.

* fix(desktop): cover repeated records and keep timestamps out of checks

An added record whose words are already in the seed still gets the list's
text when that text fits. Readiness is a start reason, so a final check
names seed locks without matching the message. Field text split by a
timestamp stays separate, and a timestamp line is not offered as a guard.

* fix(desktop): compare a cell's joined decimal within tolerance

The whole-element check keeps numeric tolerance, so 437.80 and a long
float still match 437.8, including when a run splits the digits. A
different number or other text does not. Both evaluators read an
element's text for that comparison.

* fix(desktop): keep selected logs and stop treating unknown walks as complete

Match an app name as a whole token, treat an omitted unchecked_paths count as incomplete, seed Chromium user_prefs.json, and keep a caller-selected log even when that path is also a state directory. A log inside the app's own folder still marks that folder so settings beside it stay seeded, while a lock in the home does not. Sibling locks under a selected folder stay out unless that lock was the selected path.

* fix(desktop): grade a number from a complete XML element only

A tolerance check joins an element's text only in an XML file or an XML
archive entry, and leaves that check undecided when the view is cut, so a
dropped descendant cannot turn the kept runs into a passing number. A JSON
object with the same shape stays the value itself. Equivalent decimals and a
split run on a whole cell still match.

* fix(desktop): accept an older grader only when its index helper agrees

The witness still matches a bundle whose evaluator is this REA's, or the older
index expression alone when no path segment is a leading-zero number. A
truncated verifier, a changed grader, or that older helper beside a segment
such as 01 no longer counts as the same task.

* fix(desktop): keep a lone lock a document and drop one beside its file

A selected name such as notes.lck stays a document, so launch and the draft
still treat it as the caller's file. A lock beside a recorded sibling is left
out of the seed unless that lock path itself was selected.

* fix(desktop): require the added record and leave save times out of list checks

A record a selector names is checked itself, so its words have to be in that
record. When an unnamed record only repeats words the seed already has, a
list that holds a save time is checked by the text around that time. A later
save of the same records still passes, and a missing or rewritten record fails.

* fix(desktop): judge the older index helper by pointer segments only

A leading zero in a file name or a URL does not change how the older index
helper reads a pointer. The witness still rejects that helper when a pointer
segment is a number such as 01.

* fix(desktop): keep a document whose name ends in .lock

A lock beside a recorded file still stays out of the seed unless that lock
was selected. A document such as Cargo.lock in the home is the user's file,
so the seed keeps it. An application lock in the home, such as poedit.lock,
stays out.

* fix(desktop): do not suggest list text the seed already passes

A repeated record is shown by text the seed does not hold. The seed's own
text is not a check. A pointer inside a check value is not a pointer segment
for the older index helper.

* fix(desktop): do not let a left-out lock hide settings checks

A sibling lock the seed omits is not the document the draft follows. Settings
changes stay suggested. The unused sibling-lock name helper is removed.

* fix(desktop): keep a linked settings file in the folder the link points at

A selected ~/.config alias no longer moves MuseScore settings to that alias.
The seed keeps settings/MuseScore or Documents, which is the path the export
opens the note from.

* fix(desktop): split home fetches by answer size and keep a size refusal

A batch of tiny files stops before each path's envelope exceeds the host
answer budget. A capture output past that ceiling stays a resource error
instead of becoming a generic exit.

* fix(desktop): seed a selected link under the path the app uses

The selected spelling wins, so ~/.config/MuseScore is not rewritten to the
folder it points at and the note stays the one launched document. A database
wal and journal follow that database. A launch argument is respelled the same
way. Teardown signals a detached PID only when its start identity still matches.

* fix(desktop): keep a witness's actions and an incomplete checkpoint

A failed witness save retries the action log it first recorded. A deletion
left unconfirmed between the seed and the end is not reported as no change.
Windows packs npm through a shell, which can start npm.cmd.

* fix(desktop): read verifier pointers from the parsed checks

A brace inside a check value is not an object boundary. A leading-zero
pointer after that value still rejects the older index helper.

* fix(desktop): leave out a sibling lock under a selected folder

A file under a selected folder inherits selected_path. That does not make
the lock beside its map a chosen document, so a settings change stays drafted.

* fix(desktop): prefer the most specific home spelling and retarget launch files

A selected parent directory no longer hides a settings folder walked through
a link. A launch filename under that folder is replaced with the seeded
file's absolute path.

* fix(desktop): pack the build runtime through npm's JavaScript entry

npm pack and npm ci no longer spawn npm.cmd through a shell, so a temporary
directory whose path contains spaces stays one argument.

* fix(desktop): spell launch settings and keep a database log exact

A database log matches only that file, so a neighboring folder is not moved.
A launch option and the working directory use the same home spelling as the seed.

* fix(desktop): draft a lock the export selected exactly

The draft uses the same selected paths as the export. A lock chosen by
itself stays in the draft. A lock under a selected folder stays out.

* fix(desktop): move a state database's logs with the database

The write-ahead log and journal follow the spelling the database received,
including a walked state link. A neighboring folder stays put. A separate
--config argument uses that spelling too.

* fix(desktop): keep a selected file ahead of a database-log guess

A file selected as itself keeps that spelling even when its name ends in
-journal. Relative launch arguments are resolved in the captured working
directory before that directory moves.

* fix(desktop): keep outside-home database logs and option values

A selected database outside the home keeps its write-ahead log. Launch
options are rewritten only when they name a captured file or settings path.

* fix(desktop): follow a database mapping and own limitation text

A selected database keeps its log when a parent folder moves or the file
sits outside the home. Trash and seed-lock tests compare the owning notice
with the paths, and launch options that are not captured paths stay as written.

* fix(desktop): retarget a settings folder that holds captured files

A nested profile directory is a captured path when a seeded file is inside
it. An option value that only resolves under the home stays as written.

* fix(desktop): keep a program word and a directory's neighbor

The program after env stays the program even when a captured file sits in a
folder of that name. A selected directory is not a database, so a neighboring
file keeps the parent folder's spelling.

* fix(desktop): record whether a selected path is a directory

Capture stores the walked path's kind. A neighboring file of a selected
directory keeps the parent folder's spelling even when that directory never
changes and its children are not content roots.

* fix(desktop): mark containing paths without a pairwise scan

A recorded path marks its known ancestors as directories in one walk up
the path, instead of comparing every recorded path with every other.

* fix(desktop): keep a selected folder that is named like a database log

A folder the caller selected stays a selected root when its name ends in
-journal or -wal. A generated log beside a database file still does not.

* fix(desktop): refuse a build command that exceeds the argument vector

Splitting one argument still leaves the whole command under Linux's E2BIG
limit. A request past that budget is refused before the process starts.

* fix(desktop): remap a captured path in an env assignment

The program word stays the program. A NAME=value assignment keeps its name
and follows a captured path value when that path's spelling moves.

* fix(desktop): keep oversized text out of draft guards

A value or line longer than the draft's text bound is not copied into a
guard, so one large frame cannot fill the task by itself.

* fix(desktop): keep an empty env value empty

An empty assignment is not a path. Resolving it named the working directory
and rewrote the value when that directory's spelling moved.

* fix(desktop): check build runtime export capability

* fix(desktop): provide complete runtime repack command

* fix(desktop): retain runtime probe failures

* test(desktop): identify capture independently of schema preflight

* fix(desktop): preserve document URLs and value formats

* fix(desktop): bound added checks and omit noisy text guards

* fix(desktop): preserve launch URLs and JSON draft values

* fix(desktop): recognize captured file URL documents

* fix(desktop): render captured file URLs for runtime home

* fix(desktop): distinguish phone numbers from save metadata

* fix(desktop): preserve launch URLs and user text

* fix(desktop): preserve local file URL authority

* fix(desktop): preserve local file URL authority

* fix(desktop): render captured file URLs at launch

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): retain context for generated draft values

* fix(desktop): retain context for generated draft values

* test(desktop): cover generated IDs in text guards

* test(desktop): cover generated IDs in text guards

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): retain clean text in noisy record fields

* style(desktop): format the noisy-record draft files with the pinned oxfmt

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* test(desktop): move launch execution to boundary suite

* fix(desktop): redact build schema failure output

* refactor(desktop): normalize schema failure once

* fix(desktop): omit unsafe schema parser snippets

* fix(desktop): preserve draft change and selected path evidence

* test(desktop): group retained dconf note regressions

* fix(desktop): respect archive entry format in draft checks

* test(desktop): separate unowned-file draft note cases

* fix(desktop): preserve explicitly selected journal documents

* docs(desktop): clarify task checks before scratch export

* fix(desktop): respell selected paths in file URLs

* test(desktop): group captured document spelling cases

* fix(desktop): bound draft preview serialization

* fix(desktop): restore selected state aliases

* fix(desktop): respect entry format in draft noise

* test(desktop): match exported alias evidence at its JSON boundary

* fix(desktop): retain app state logs in exported seeds

* style: fix desktop launch test formatting

* style: format native command path schema

* fix(desktop): map selected external launch paths

* style(desktop): format seed document regressions

* test(desktop): group launch URL regressions

* fix(desktop): omit redundant nested state aliases

* fix(desktop): compare added free text as a whole

* fix(desktop): check recompressed seeds as shipped

* docs(desktop): clarify recovered seed format

* test(desktop): group shipped gzip seed checks

* fix(desktop): map captured launch paths once

* refactor: remove unused whole-text guard state

* refactor: stop passing unused text children

* test: align free-text checks with whole-note policy

* fix: validate recompressed desktop archive seeds

* style(desktop): format archive seed regression

* fix(desktop): redact runtime schema errors

* fix(desktop): normalize captured file URLs

* fix(desktop): report seeded files by capture path

* fix(desktop): retain startup readiness failure stage

* fix(desktop): retain JSON date checks

* fix(desktop): preserve archive formatting checks

* fix(desktop): preserve explicitly selected journal files

* fix(desktop): report build command transport limits

* docs(desktop): clarify unreadable dconf versions

* style(desktop): format capture review fixes

---------

Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: morluto <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-09 22:51:50 +08:00
Evtim Kostadinovandmorluto eb8ba20c35 docs(i18n): add Bulgarian README (#9656)
* docs(i18n): add Bulgarian README

Add a complete Bulgarian (bg) translation of the README and list it in
every README language bar and the website language inventory.

Register bg with a pending website catalog that uses the labeled,
nonindexable English fallback, with the fallback notice translated.
Regenerate the shared language picker and hreflang links and refresh
messages.pot.

* docs(i18n): clarify Bulgarian project code license scope

---------

Co-authored-by: morluto <[email protected]>
2026-11-09 09:13:49 -05:00
Nianze Wuandmorluto bdf7cc3b1e fix(pe): reject malformed certificate name structures (#9625)
* fix(pe): reject malformed certificate name structures

* fix(ci): bound the complete Kuna verifier workflow

---------

Co-authored-by: morluto <[email protected]>
2026-11-09 22:09:34 +08:00
吴佳浩Albenandmorluto 3b2522bd3b fix(javascript): reject a tls protocol version Node refuses at the call site (#9557)
* fix(javascript): reject a tls protocol version Node refuses at the call site

`tls.connect` resolves `minVersion`/`maxVersion` before it opens a socket, so a bad literal
throws from the call itself and no socket exists. The acquisition filter decided the port
only, so it reported a complete built-in resource for a call that throws.

Measured on Node 24.22.1:

| `minVersion` / `maxVersion` | outcome |
| --- | --- |
| `"TLSv1"`, `"TLSv1.1"`, `"TLSv1.2"`, `"TLSv1.3"` | socket created |
| `null`, `undefined`, absent | socket created |
| `"TLSv1.0"`, `"tlsv1"`, `"tlsv1.2"`, `"TLSv1.4"`, `"nope"`, `""` | THREW `ERR_TLS_INVALID_PROTOCOL_VERSION` |
| `5`, `true`, `{}`, `[]` | THREW `ERR_TLS_INVALID_PROTOCOL_VERSION` |
| `1n` | THREW `TypeError` |

The accepted set is exact and case-sensitive, so it is a closed list rather than a pattern.
`net` ignores these members, so only `tls` is consulted. The member is read in write order,
which is why `{minVersion: "nope", minVersion: "TLSv1.2"}` keeps its acquisition; a spread,
a computed key or an accessor leaves the answer undecided rather than decided against.

22 cases, 11 failing before this commit. `src/domain/javascript`: 5040 to 5062 passing.
`tsc` 0; `build` 0; `npm run format:check` 0; `npm run lint` 0 errors; `knip` 0.

* fix(javascript): read every tls options slot and check both version members

Four review findings, each measured on Node 24.22.1. All four were real gaps in the first
version of this check.

**An accepted `minVersion` returned before `maxVersion` was read.** `tls.connect({port: 80,
minVersion: "TLSv1.2", maxVersion: "nope"})` throws, because both members are resolved
before the socket opens. The loop now continues past an accepted version and returns only
for a rejected one.

**Only argument zero was read.** `tls` also accepts `(port, options)`, `(port, host,
options)` and `(path, options)`, and all three throw on a bad version:
`tls.connect(443, {minVersion: "nope"})`, `tls.connect(443, "127.0.0.1", {minVersion:
"nope"})` and `tls.connect("/tmp/x.sock", {minVersion: "nope"})`. Every object literal in
the argument list is now read; a spread argument shifts those positions, so it leaves the
answer undecided instead of picking a wrong slot.

**A signed number was left unknown.** `minVersion: -1`, `+1` and `-0` all throw, but they
arrive as a `UnaryExpression` and matched none of the literal arms. `readExactJavaScriptLiteral`
already normalises `-1` and `+1`; `-0` is the one case it excludes, so a sign over a numeric
literal is decided explicitly here rather than treated as unknown.

13 cases added; reverting the slot and loop changes fails 4 of them.
`src/domain/javascript`: 5062 to 5075 passing. `tsc` 0; `build` 0;
`npm run format:check` 0; `npm run lint` 0 errors; `knip` 0.

* fix(javascript): merge the tls arguments and honour a supplied secure context

Four review findings, each measured on Node 24.22.1. All four were real: the previous
reader checked each object argument independently and ignored the context.

**Several object arguments merge in order, so the later one wins.** The reader rejected the
first object and stopped:

| call | Node 24.22.1 |
| --- | --- |
| `tls.connect({port: 443, minVersion: "nope"}, {minVersion: "TLSv1.2"})` | SOCKET |
| `tls.connect({port: 443, minVersion: "TLSv1.2"}, {minVersion: "nope"})` | THREW |
| `tls.connect({port: 443}, {minVersion: "nope"})` | THREW |

The members are now resolved across the whole argument list in write order, so a later
argument replaces an earlier one the way Node's merge does.

**A supplied `secureContext` bypasses version parsing entirely.** Node uses
`options.secureContext || tls.createSecureContext(options)`, so
`tls.connect({port: 80, secureContext: ctx, minVersion: "nope"})` connects while a `null`
context throws. An unreadable context leaves the answer undecided.

**An ordinary method member cannot install a version.** The reader skipped any object
containing a method, so `{checkServerIdentity() {}, minVersion: "nope"}` kept a socket
Node never creates. Only an accessor runs a body and leaves the member open; a plain method
is a value Node never reads as a version name. A `minVersion() {}` member is itself such a
value, so it rejects.

**Signed BigInt and function-shaped versions were left unknown.** `-1n`, `() => {}`,
`function () {}` and `class {}` are all truthy non-strings that Node refuses; none matched
an existing arm. They are now decided.

12 cases added; reverting the merge and context changes fails 2 of them and reverting the
method arm fails 6. `src/domain/javascript`: 5075 to 5087 passing. `tsc` 0; `build` 0;
`npm run format:check` 0; `npm run lint` 0 errors; `knip` 0.

* fix(javascript): read only the options slot tls.connect copies, and its accessors

Six review findings, each measured on Node 24.22.1. All six were real.

**A falsy `secureContext` does not bypass version parsing.** Node tests
`options.secureContext` for truth, so `{secureContext: false, minVersion: "nope"}`, and `0`
and `""` with it, all throw. The guard only recognised nullish syntax, so it dropped real
throws. `staticTruthiness` now decides the context: a known-falsy value keeps checking, a
known-truthy one ends the check, and an unreadable one stays undecided.

**Node copies at most one options object.** Measured:

| call | result |
| --- | --- |
| `(443, {minVersion: "TLSv1.2"}, {minVersion: "nope"})` | SOCKET — the third argument is ignored |
| `(443, {minVersion: "nope"}, {minVersion: "TLSv1.2"})` | THREW |
| `(443, "127.0.0.1", {minVersion: "nope"})` | THREW — the host fills slot 1 |
| `({port: 443, minVersion: "nope"}, {minVersion: "TLSv1.2"})` | SOCKET — the second object wins |

The reader treated every object argument as merged in order, which let an ignored object
decide. `tlsOptionsObjects` now models the two overloads: an object in slot 0 is merged with
slot 1, and a port or path in slot 0 makes the first object among slots 1 and 2 the only one
read.

**An exact computed key names the member.** `{["minVersion"]: "nope"}` throws, but the
reader marked every computed key unknown before the shared name resolver saw it. Only an
unresolvable key is unknown now, and the case that asserted the old behaviour uses a
binding key so it still covers the unknown path.

**An accessor can write the member first.** `{get side() { this.minVersion = "TLSv1.2"; },
minVersion: "nope"}` connects, because Node's own copy runs the getter before it reads
`minVersion`; and a `set minVersion` in an earlier argument absorbs the later write. Both
are bodies this reader does not run, so an accessor anywhere in the merged objects now
leaves every version member undecided. A plain method still rejects, since Node never reads
it as a version name.

**An unshadowed `NaN` or `Infinity` is a non-string version.** Both throw, and neither
matched an existing arm. They are decided the same way the adjacent port filter decides
them, through `isUnmodifiedGlobalReference`, so a shadowed binding stays unknown.

16 cases added; reverting the truthiness, accessor and computed-key changes fails 2 of them.
`src/domain/javascript`: 5075 to 5188 passing. `tsc` 0; `build` 0;
`npm run format:check` 0; `npm run lint` 0 errors.

* fix(javascript): use the nullable key owner and settle unary versions

Six review findings, each measured on Node 24.22.1. All six were real, and three of them
were removing real sockets.

**`semanticStaticPropertyName` encodes an unresolved key as `""`, never `undefined`.** The
guard tested `undefined`, so it never fired and an unresolved computed key was read as a
member literally named empty. `const k = "minVersion";
tls.connect({port: 443, minVersion: "nope", [k]: "TLSv1.2"})` connects on Node 24.22.1
because the later computed member wins, while the analysis filtered on the stale `"nope"`
and dropped the socket. `semanticStaticPropertyKey` is the nullable owner and is now used,
with `null` treated as unknown.

**A getter can replace a plain version method before Node copies it.** The method branch
ignored `accessorWritten`, so `{get side() { this.minVersion = "TLSv1.2"; }, minVersion()
{}}` still returned `"rejects"` although it connects. The same unknown result now applies to
methods when an accessor is present.

**A non-literal second argument is a merged options object, not an absent one.**
`const o = {minVersion: "TLSv1.2"}; tls.connect({port: 443, minVersion: "nope"}, o)`
connects. The slot reader mapped every non-object to `undefined`, so only the stale first
object was examined. A non-object in a copied slot now stays unknown.

**`-0` is falsy, so a signed-zero context does not bypass parsing.** The local truthiness
helper did not fold a unary `-`, so `{secureContext: -0, minVersion: "nope"}` was treated as
a possible bypass although it throws. The shared `staticJavaScriptTruthiness` owner already
handles signed zero and replaces the local helper, which is deleted.

**A unary operator over a settled operand is a settled non-string version.** `!0`, `!1`,
`~~0`, `!!0` and `typeof 1` all throw `ERR_TLS_INVALID_PROTOCOL_VERSION`; the previous arm
recognised only `+` and `-`, and the exact-literal and shape arms did not reach them.
`void <expr>` stays accepted, because it is `undefined`.

The slot reader also had to distinguish a host string in slot 1 from an options object, since
`tls.connect(443, "127.0.0.1", {minVersion: "nope"})` throws while
`tls.connect(443, {minVersion: "nope"})` is the two-slot form.

`src/domain/javascript`: 5188 to 5197 passing. Reverting the key owner fails 1 case and
reverting the unary arms fails 2. `tsc` 0; `build` 0; `npm run format:check` 0;
`npm run lint` 0 errors.

* test(javascript): distinguish package scope in route fixtures

* test(apple): separate identity and refusal fixture groups

* fix(javascript): share TLS option facts and preserve merge uncertainty

* fix(javascript): separate TLS assignment authority from copy facts

---------

Co-authored-by: morluto <[email protected]>
2026-11-09 22:09:29 +08:00
8bc01b48b4 feat(native): list ELF and Mach-O initializer and finalizer functions (#9574)
* feat(native): list ELF and Mach-O initializer and finalizer functions

inspect_native_initializers and inspect-native-initializers list the
functions an ELF or Mach-O image runs before and after main: ELF
DT_INIT, DT_FINI, preinit, init and fini arrays and .ctors/.dtors, and
Mach-O __mod_init_func, __mod_term_func and __init_offsets, with slot
addresses, resolved targets, symbols where available and relocation
facts for relocatable objects. Nothing is executed. Slot, symbol,
relocation and note budgets are shared across tables, sentinels are
matched at the image width, and target-derived names are bounded and
marked untrusted.

* fix(native): keep ELF initializer slots unresolved when relocation coverage is partial

A skipped, unreadable or over-budget section relocation table now keeps
every slot it could reach unresolved instead of reading the stored word as
raw or dropping a .ctors slot as a sentinel. Dynamic writes that only
partly overlap a slot, or write it twice, leave it unresolved. Linked
images no longer reapply retained non-SHF_ALLOC link-time records.

The dynamic relocation walk now pauses at the shared reader's step
boundaries and observes cancellation there, resolved targets need only
their first byte mapped, and unreadable symbol names make the report
incomplete.

* fix(native): stop reporting unchecked Mach-O initializer words as resolved

Object files now apply their own section relocations: an UNSIGNED entry
against a defined symbol gives symbol_addend, one against an undefined
symbol gives unresolved_import, and any other entry leaves the slot
unresolved. Linked images without a fixup decoder, such as 32-bit ones,
keep pointer slots unresolved when an LC_DYLD_INFO bind stream or
LC_DYSYMTAB external relocations could replace the stored word.

LC_DYLD_INFO rebases now report dyld_info_rebase instead of
chained_fixup, and unreadable symbol names make the report incomplete.
Section headers keep their declared reloff and nreloc for this.

* docs(native): move initializer guide under docs/guides/native

The documentation guide assigns analyst workflows to docs/guides/<domain>/.
Move the guide there, place its navigation and directory entries in the
Native binaries group, and update links from the docs index, CLI guide,
spec and authored skill. The public /native-initializers route is
unchanged.

The guide and spec also describe per-slot relocation coverage, retained
link-time records, Mach-O object relocations, undecoded bind streams,
the dyld_info_rebase resolution and unreadable names.

* fix(native): keep IFUNC and partly relocated ELF initializer slots unresolved

An absolute relocation against an STT_GNU_IFUNC symbol no longer reports
the resolver address as the target. Section relocation records now use
their real write width, so a record that writes only part of a slot,
starts inside it or repeats it leaves the slot unresolved instead of
reading a raw zero or dropping a .ctors slot as a sentinel.

On 32-bit ARM the Thumb bit is cleared when locating a target's section
and file offset, while value_va keeps the stored callable value.

* fix(native): locate Thumb Mach-O initializer targets and reject arm64_32 with a 64-bit header

On CPU_TYPE_ARM the Thumb bit is cleared when locating and naming a
target, since nlist values do not carry it. An arm64_32 image that
declares a 64-bit header is rejected as malformed rather than read with
8-byte slots. The guide and spec describe IFUNC relocations, partly
relocated section slots, Thumb targets and this rejection.

* fix(native): index initializer address lookups and keep ambiguous mappings unknown

ELF and Mach-O initializer lookups now build the shared file mapping
index once per image, so each slot and target lookup is logarithmic in
the number of load segments rather than a scan of every mapping.

An address that load segments map ambiguously no longer falls back to a
section header offset. Its file offset is reported as unknown and the
report is incomplete; only genuinely unmapped spans use the section
fallback.

* fix(native): report Mach-O bind names over the name budget

A bound import name longer than the 1024-byte name budget was dropped
without a trace, although it is the only identity of an unresolved
initializer target. It now counts toward the over-long name limitation
and makes the report incomplete.

* test(native): count mapping lookups instead of timing the load index regression

The load-mapping regression asserted a wall-clock bound, which is
sensitive to machine load. It now spies on the shared mapping module and
requires the same number of mapping scans and index builds for 8 and 64
slots, so a per-slot scan of every load segment fails deterministically
on a small fixture.

* fix(native): yield while decoding legacy rebase runs

* fix(native): preserve initializer mapping and coverage

* fix(native): index legacy fixup spans

* fix(native): preserve relocation uncertainty and bound bind lookup work

* fix(native): validate ELF slot mappings and yield section relocation scans

---------

Co-authored-by: Matt Van Horn <[email protected]>
Co-authored-by: morluto <[email protected]>
2026-11-09 08:58:12 -05:00
morluto deae5fbe6d docs: correct workflow claims and clarify historical specifications (#9655)
* docs: correct lifecycle and analysis workflow claims

* docs: distinguish historical specifications from current guides

* docs: align translated setup and MCP recovery guidance
2026-11-09 08:54:23 -05:00
fa0fcf35ce fix(desktop): resolve desktop entry ids that name a nested entry (#9563)
* fix(desktop): resolve desktop entry ids that name a nested entry

The desktop file id of an entry below an applications folder replaces
the directory separators with dashes, so applications/vendor/foo.desktop
advertises vendor-foo.desktop. locateDesktopEntry only probed the flat
path, so such an entry was either not found or, when a lower-priority
XDG root installed a flat file with the same id, a different
application was launched under the requested id.

List each applications directory instead and form every entry's id from
the path that holds it, so a dash inside a directory name does not
change the answer. The walk is bounded and stops reporting absence once
it can no longer decide, so a truncated search refuses instead of
falling through to a lower-priority root.

* fix(desktop): search nested entry directories without skipping answers

Three defects in findNestedDesktopEntry, all of which could select a lower-priority application under the same desktop file id:

`readdir` failure was treated as an empty directory, so an applications root or nested directory that could not be listed silently yielded to a lower-priority root. Only ENOENT and ENOTDIR now mean the root is not installed; any other failure reports desktop_entry_search_incomplete.

A directory whose own name ends in `.desktop` was skipped before it was searched, so `vendor.desktop/app.desktop` (id `vendor.desktop-app.desktop`) was unreachable. The suffix now selects a candidate only for files; directories still descend.

The entry budget was applied after `readdir` had materialized every name, so a large directory allocated far more than the 4096 entries it may examine. The walk now enumerates with `opendir` and charges the budget per entry.

* fix(desktop): finish the reachable nested search before reporting a gap

An unreadable or over-budget subtree is not proof the entry is absent, but
returning truncated as soon as one was met stopped the walk before the
siblings that could still hold it. The entry then looked incomplete even
though this root could answer, so a lower-priority root was never consulted
and the search reported a gap instead of the entry.

* test(javascript): distinguish package scope in route fixtures

* test(apple): separate identity and refusal fixture groups

* fix(desktop): resolve only applicable desktop ID paths

* test(desktop): cover applicable probe failure before a matching spelling

---------

Co-authored-by: 2SinceJuly <[email protected]>
Co-authored-by: morluto <[email protected]>
2026-11-09 21:47:20 +08:00
217b6fdcdc feat(cli): expose provider selection diagnostics in session status (#9603)
* feat(cli): expose provider selection diagnostics in session status

The registry now records how each deep provider became selected and why a
candidate was rejected, but the session status projection dropped both
fields. CLI providers/capabilities and MCP binary_session therefore showed
a candidate list that could not explain an automatic or explicit choice,
so users had to re-derive the reason from prose in selection errors.

Project selection_source and rejections for every candidate. Complete detail
keeps the rejection remediation and diagnostics; summary keeps the stable
origin, code and reason and lists the dropped fields in omitted_fields.
Existing candidate fields are unchanged, so both projections stay additive.

* test(javascript): distinguish package scope in route fixtures

* test(apple): separate identity and refusal fixture groups

* fix(session): preserve binding source in refreshed candidates

---------

Co-authored-by: 2SinceJuly <[email protected]>
Co-authored-by: morluto <[email protected]>
2026-11-09 21:47:15 +08:00
Harsh Asalkarandmorluto 78343052c2 fix(mcp): narrow union branch diagnostics to matching discriminators (#9481) (#9587)
* fix(mcp): narrow union branch diagnostics to matching discriminators

* fix(mcp): merge union expected options at identical diagnostic paths

* fix(mcp): guide cross-kind sub-selector mistakes on inspect_analysis_view

* fix(mcp): support heterogeneous strict object variants in union discriminator narrowing

* fix(mcp): resolve union discriminators before narrowing and preserve nested alternatives

* fix(mcp): resolve setting discriminator before narrowing and preserve invalid_type failures

* fix(mcp): narrow branches by matched discriminators before synthesizing diagnostics

* test(javascript): distinguish package scope in route fixtures

* test(apple): separate identity and refusal fixture groups

* fix(input): preserve selector failures within projection bounds

---------

Co-authored-by: morluto <[email protected]>
2026-11-09 21:47:09 +08:00
Cipherandmorluto b105dae7c6 test(mcp): pin Kimi/Moonshot-accepted input schemas for #9581 (#9592)
* test(mcp): pin Kimi/Moonshot-accepted input schemas for #9581

Closes #9581

#9581 reports Kimi/Moonshot rejecting 9 tools whose input schemas
carried a $ref to a oneOf/anyOf with a nested $ref. The inlined
advertisement that fixes this is already on main (reused: "inline"
in toolInputSchemaWithMetadata, 554816be, unreleased): all 246
advertised input schemas are reference-free in both profiles. This
adds the regression coverage that pins it: the issue's minimal
trigger through the compact presenter, and the rejected reference
pattern checked across every served input schema in both profiles,
naming the nine tools from the issue.

Not verified against live Kimi/Moonshot (no access); verified locally
that no advertised input schema in either profile contains the
rejected pattern.

* test(javascript): distinguish package scope in route fixtures

* test(apple): separate identity and refusal fixture groups

* test(mcp): qualify reference detector and semantic inlining

---------

Co-authored-by: morluto <[email protected]>
2026-11-09 21:47:03 +08:00
吴佳浩Albenandmorluto 7a1d89a801 fix(javascript): reject child-process option literals Node refuses at the call site (#9594)
* fix(javascript): reject a spawn stdio string Node refuses at the call site

`node:child_process` validates a literal `stdio` string before it creates anything, so a
bad value throws from the call itself and no child process exists. The analysis reported the
raw string as `stdioMode` and kept the spawn.

Measured on Node 24.22.1:

| `stdio` | outcome |
| --- | --- |
| `"pipe"`, `"overlapped"`, `"inherit"`, `"ignore"` | child starts |
| `"ipc"`, `"PIPE"`, `"pipe "`, `"pipeline"`, `"stream"`, `"stdio"` | THREW `ERR_INVALID_ARG_VALUE` |

The accepted set is exact and case-sensitive, so it is a closed list rather than a pattern.
`"ipc"` is the interesting one: it is valid as an array element but refused as the scalar
shorthand, which is the shape a caller reaches for when they mean the array form.

`fork` differs on one value because it appends `"ipc"` to a string and splits it, so `""`
becomes the lone element `"ipc"` and is refused:

| call | outcome |
| --- | --- |
| `spawn(..., {stdio: ""})` | child starts |
| `fork(..., {stdio: ""})` | THREW `ERR_INVALID_ARG_VALUE` |

`exec` is left alone, because it spreads its options and validates none of them. A number,
boolean or object `stdio` is also refused by Node, but `stdioMode` already reports those as
`"dynamic"`; deciding them here would claim more than the reported mode explains, so only
the string case is decided.

18 cases, 9 failing before this commit. `src/domain/javascript`: 5106 to 5124 passing.
`tsc` 0; `build` 0; `npm run format:check` 0; `npm run lint` 0 errors.

* fix(javascript): reject a non-string cwd or argv0 Node refuses at the call site

The same call-site validation the `stdio` string gets applies to `cwd` and `argv0`:
Node checks them before the child exists, so a non-string literal throws
`ERR_INVALID_ARG_TYPE` and the analysis still reported a spawn.

Measured on Node 24.22.1, identical on `spawn`, `fork`, `execFile` and `exec`:

| `cwd` / `argv0` | outcome |
| --- | --- |
| `"/tmp"` / `"x"` | child starts |
| `null` | child starts |
| `5`, `0`, `true`, `{}`, `[]` | THREW `ERR_INVALID_ARG_TYPE` |

`env` is deliberately not in the set: Node accepts any `env` value, including `5` and
`"x"`, so a non-object `env` is not a call-site failure.

Only an exactly readable literal is decided; a binding, a call or a member read stays
undecided, because its value is not settled by this expression.

The test file is renamed from `spawn_stdio_literal` to `spawn_option_literals` because it
now covers all three members. 16 cases added; reverting this check fails 9 of them.
`src/domain/javascript`: 5124 to 5140 passing. `tsc` 0; `build` 0;
`npm run format:check` 0; `npm run lint` 0 errors.

* fix(javascript): read the stdio and path options by value, not by AST kind

Seven review findings, each measured on Node 24.22.1. All seven were real, and two of them
were removing real children.

**`execFile` does not forward `stdio`.** Async `execFile` never passes `options.stdio` to its
underlying `spawn`, so `execFile(process.execPath, ["-e", ""], {stdio: "bad"})` returns a
real child — `stdioMode` already forces it to `"default"`. The new filter rejected it anyway
and dropped the spawn plus its linked interactions. `execFile` is now exempt, like `exec`.

**A no-substitution template literal is the same string to Node.** `readExactJavaScriptLiteral`
already resolves it, but the filter tested `t.isStringLiteral`, so ``{stdio: `ipc`}`` kept a
spawn Node refuses while ``{cwd: `/tmp`}`` — a valid path — was rejected because the same
branch called `readExactJavaScriptLiteral` and treated any hit as a non-string. Both sides
now read the value and test its type:

| call | Node 24.22.1 |
| --- | --- |
| ``spawn(..., {stdio: `ipc`})`` | THREW `ERR_INVALID_ARG_VALUE` |
| ``spawn(..., {stdio: `pipe`})`` | child starts |
| ``spawn(..., {cwd: `/tmp`})`` | child starts |
| ``spawn(..., {argv0: `x`})`` | child starts |

**A shape the literal owner does not price still has a settled type.** `{cwd: 1n}`,
`{cwd: /x/}`, `{cwd: () => {}}`, `{cwd: class {}}` and `{cwd: new String("x")}` all throw
`ERR_INVALID_ARG_TYPE`, and none matched the previous object/array/boolean arms.

**The `fork` explanation was wrong.** Node's `stdioStringToArray` rejects `stdio: ""` with an
explicit check before anything is appended; it does not split the string and it never builds
an IPC-only array. The rejection was right, the reason was not, so the comment now states the
real rule.

44 cases; reverting the `execFile` exemption fails 1, reverting the value-based read fails 1,
and reverting the extended non-string arms fails 6.
`src/domain/javascript`: 5158 to 5168 passing. `tsc` 0; `build` 0;
`npm run format:check` 0; `npm run lint` 0 errors.

* fix(javascript): keep a path-shaped cwd that Node accepts

`cwd` is a path, so Node takes a byte array or a file `URL` there, not only a string. The
blanket `NewExpression` arm rejected every constructor for both members, which dropped real
children.

Measured on Node 24.22.1, identical on `spawn`, `fork`, `execFile` and `exec`:

| `cwd` | outcome |
| --- | --- |
| `new Uint8Array([47, 116, 109, 112])` | child starts |
| `new Buffer("/tmp")` | child starts |
| `new URL("file:///C:/tmp/")` | child starts |
| `new String("/tmp")`, `new Number(1)`, `new Foo("/tmp")` | THREW `ERR_INVALID_ARG_TYPE` |

`argv0` is different: it is an argument string only, so `new Uint8Array([120])` and
`new URL(...)` both throw there. `isPathConstructor` names the constructors that can produce
a path, and only `cwd` consults it.

`URL` stays undecided rather than accepted, because whether a file URL resolves is a
platform property: `new URL("file:///tmp/")` throws `ERR_INVALID_FILE_URL_PATH` on Windows
while a drive-qualified path does not. Syntax alone cannot settle that, so the answer is
left open instead of guessed.

8 cases added; reverting the arm fails 3 of them.
`src/domain/javascript`: 5168 to 5176 passing. `tsc` 0; `build` 0;
`npm run format:check` 0; `npm run lint` 0 errors.

* test(javascript): distinguish package scope in route fixtures

* test(apple): separate identity and refusal fixture groups

* fix(javascript): keep unresolved cwd constructors unknown

* refactor(javascript): name process option admission by its contract

---------

Co-authored-by: morluto <[email protected]>
2026-11-09 21:46:57 +08:00
Nianze Wuandmorluto 759817ccbe fix(javascript): distinguish Promise and FileHandle releases (#9584)
* fix(javascript): distinguish Promise and FileHandle releases

* fix(javascript): preserve reassigned handle candidates

* test(javascript): select unisolated route fixtures explicitly

* test(javascript): distinguish package scope in route fixtures

* test(apple): separate identity and refusal fixture groups

* fix(javascript): retain uncertain releases after opaque receiver writes

---------

Co-authored-by: morluto <[email protected]>
2026-11-09 21:46:51 +08:00
RRFZandmorluto da3bb5aa7b fix(managed): report InternalCall methods as runtime-provided boundaries (#9547)
* fix(managed): report InternalCall methods as runtime-provided boundaries

inspect_managed_native_boundaries listed P/Invoke, native, runtime and
unmanaged methods, but not methods with MethodImplOptions.InternalCall
(0x1000). The runtime implements those bodies; mscorlib and
System.Private.CoreLib declare hundreds of them as FCalls. They now appear
in native_implementations with boundary_kind runtime-provided.

* fix(managed): keep InternalCall bodies out of CIL decoding

The native-boundary view reports InternalCall methods as runtime-provided.
Body admission still decoded CIL from a nonzero RVA when the row kept IL
and managed flags. CoreCLR rejects such a row (BFA_INTERNAL_METHOD_WITH_RVA).

Body admission now treats InternalCall like the Runtime code type. The
method gets a partial body with no instructions. The InternalCall test
covers both a zero and a nonzero RVA.

* test(javascript): distinguish package scope in route fixtures

* test(apple): separate identity and refusal fixture groups

* fix(managed): honor InternalCall during body admission

---------

Co-authored-by: morluto <[email protected]>
2026-11-09 21:46:45 +08:00
RRFZ ec7d09176b fix(mcp): retain partial Playwright trace Evidence on failed imports (#9543) 2026-11-09 21:46:39 +08:00
RRFZ bf1811bdbc test(electron): expect the native path of an authorized ASAR file (#9549) 2026-11-09 21:46:34 +08:00
RRFZ 74201434e7 test(ida): expect Windows to fold a missing parent in the workspace root (#9548)
The IDA doctor test selects workspaceRoot `<root>/missing/..` and expects
the workspace to be unavailable. Windows folds `..` lexically before the
filesystem sees the path, as workspace allocation does, so the parent is
usable there and the test failed on every Windows run. Keep the POSIX
expectation and accept availability on Windows.
2026-11-09 21:46:30 +08:00
RRFZ 769d92025d fix(ida): report the regex syntax error for invalid search patterns (#9544)
IDA checks a regex search pattern before it starts the provider. That early
check returned a generic "Supply a valid regular expression." issue, so IDA
callers never saw the parser explanation or the literal-mode recovery that
the shared regex worker gives Kuna and Hopper callers.

Build both refusals with one helper in RegexMatcher.
2026-11-09 21:46:25 +08:00
RRFZ ca1674473c fix(rust): read rustc commit paths written with a Windows separator (#9542) 2026-11-09 21:46:20 +08:00
22f28644fe feat(artifacts): inventory and extract Deno compile executables (#8527)
* feat(artifacts): inventory and extract Deno compile executables

Adds Deno standalone artifact support for Mach-O, ELF, and PE carriers,
exposing virtual files, entry points, recorded options, and file digests
without running the executable. Extraction uses the existing safe output
tree, preserves symlink targets as metadata, and assigns indexed paths
to unsafe or oversized names. Environment-file values and certificate
bytes remain in local Evidence; npm snapshots are reported by length
without decoding. The documentation describes supported layouts, parsing
limits, and refusal behavior.

* fix(artifacts): resolve nested Intel Deno carriers to the enclosing app

The backward trailer search stopped at the first confirmed sentinel, so an
Intel app storing another Intel Deno executable as a virtual file reported
the inner app. Search to the slice start, drop sentinels inside a confirmed
payload, and fail closed on side-by-side trailers that differ.

Correct the docs on retained environment values and generated regions.

* fix(artifacts): keep Deno coverage, remote paths and PE resources truthful

Report unknown coverage when the virtual filesystem cannot be listed, keep
resolved specifiers when another remote ID is missing, and percent-encode
characters in remote paths that a Windows destination would refuse. Reject a
directory at the PE resource language level, and correct the guide's
description of colliding generated regions.

* fix(artifacts): normalize Deno remote escapes so hex case cannot collide

Uppercase every percent escape in a generated remote path, so specifiers that
differ only in escape case reach the path registry as one name and the second
gets an indexed path instead of colliding on a case-insensitive disk.

* fix(artifacts): fail closed on truncated enclosing Deno trailers and encode reserved remote path characters

The Intel trailer scan rejected an overlong sentinel before reading its
marker, so a truncated enclosing app vanished and the nested app was
reported. Read the marker first and fail closed when a confirmed overlong
trailer encloses another trailer.

encodeURIComponent leaves `*` alone and the sanitizer covered only part of
the Windows reserved set. remoteDestination now encodes the whole set once
as uppercase percent hex; source_path keeps the original.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01KuWHGvzJkrhCqjtEHUwqyH

* fix(artifacts): defer truncated Intel Deno trailer failure until enclosing trailers resolve

A damaged Intel asset stored before a valid one inside a valid app made the
backward trailer search fail before it reached the outer trailer. Hold that
failure until the search ends and drop it when a confirmed enclosing trailer
holds the sentinel as data.

* fix(pe): fail closed when a resource type branch is unreadable beside a found name

namedResourceTargets skipped a type branch whose names directory, or a
name entry whose string, could not be read. A duplicate RT_RCDATA entry
pointing out of bounds therefore vanished once another branch matched,
and locatePeResourcePayloads returned only the readable ranges while
parsePeResources rejected the same tree.

The walk now records unresolved branches. hasPeResourceName still
reports false for a tree that never reaches the name, but once
locatePeResourcePayloads finds the name it raises a format failure if
any branch was left unresolved.

* fix(artifacts): skip Intel Deno sentinels that a native segment maps

A non-Deno x86_64 Mach-O that stores an Intel Deno executable in __DATA
had the asset's trailer promoted to the root application, because the
backward sentinel search never checked who owned the bytes it scanned.

locateMachOSlice now records the file ranges of every segment other than
__SUI and __LINKEDIT (libsui extends __LINKEDIT over the trailer), and
the Intel search skips any sentinel inside one of them. A slice whose
load commands do not frame stays with native inventory, since ownership
cannot be shown there.

* fix(artifacts): reject a universal Deno image with an unreadable sibling slice

The universal Mach-O locator skipped any slice whose load commands could
not be read or framed, and any slice with a FAT range issue. When another
slice confirmed Deno, that slice was reported as the whole image, so a
sibling declaring a different Deno application went unexamined.

locateMachOSlice now reports why part of a slice was not examined
(unreadable or unframed load commands, a truncated slice, or the Intel
sentinel allowance). locateMachO collects those reasons for every
declared and hidden slice and fails closed once any slice confirms a
Deno section. With none confirmed, the image stays with native inventory
as before.

* fix(scripts): supervise the Deno verifier version check

Run `deno --version` through the verifier command owner with a deadline
instead of raw execFile, and close the owner when the version is refused.

* fix(artifacts): keep unconfirmed Deno carriers native and fail truncated Intel trailers

An ELF SUI note whose descriptor is too short for the full d3n0l4nd name
now stays unconfirmed instead of failing closed; failures after the name
matches still fail closed.

Every marker-confirmed Intel trailer whose payload runs past the slice is
now kept until the backward search ends and fails unless an enclosing
payload contains it, so an Intel Deno app missing its last byte reports a
Deno failure instead of native inventory.

The Deno MCP boundary test now calls open_binary and inspect_artifact
through artifactMcpCall, as docs/testing.md requires.

* test(deno): drop source-text checks from verifier pin test

Keep the wrong-version subprocess check, which covers the pinned
release through behavior, and stop asserting on the verifier script's
source spelling.

* test(deno): close readers in finally in symlink and cancellation tests

A failed assertion or read error in either test skipped reader.close(),
leaving the file open while temp-directory cleanup ran. Both tests now
close the reader in finally, as CONTRIBUTING.md requires. The
closed-reader assertion in the symlink test stays after the finally.

* docs(specs): add deno-standalone spec, plan and tasks

Add docs/specs/artifacts/deno-standalone/ with spec.md, plan.md and
tasks.md for the Deno compile executable reader, as AGENTS.md requires
for a feature, and list them in the specifications index.

* docs: list the Deno compile guide in the documentation sidebar

* fix(deno): confirm the d3n0l4nd section before claiming Mach-O damage

A __SUI segment alone no longer makes later load-command damage Deno's.
A Mach-O whose __SUI segment holds only a differently named section now
stays absent and keeps native inventory, while damage seen before or
beside a confirmed d3n0l4nd section still fails closed.

* fix(deno): keep a slice with an unparsed segment command unread

A Mach-O segment command that frames but cannot be parsed may be the
__SUI segment, so the slice is no longer treated as fully examined. A
universal image whose other slice confirms Deno now fails closed instead
of letting that sibling supply the whole inventory, and with no confirmed
sibling the image still keeps native inventory.

* fix(deno): confirm an ELF SUI note before rejecting its length

A SUI note whose descsz runs past its note table was recorded as plain
damage before its descriptor name was read, so a malformed Deno carrier
fell back to native inventory. The owner and the d3n0l4nd name prefix are
now read within the table apart from the claimed extent, and a confirmed
note with an oversized extent fails closed.

* fix(deno): confirm a truncated __SUI section record by its name

A section record cut short after its 16-byte name was skipped, so a
damaged Deno carrier fell back to native inventory. The name is now read
apart from the rest of the record, and a truncated record that names
d3n0l4nd fails closed. The range checks for a confirmed record move into
their own helper.

* fix(deno): reject nonzero bytes after the last ELF note

When fewer than 12 bytes remained in a note table after its last note,
the walk stopped without looking at them, so a Deno note was selected
with complete coverage beside unaccounted data. The remainder is now
read: zero padding is accepted, and nonzero bytes are recorded as damage,
which fails closed once a SUI note is confirmed and otherwise leaves the
ELF to native inventory, matching the native note parser.

* fix(deno): validate FAT slice identity before choosing the search

The locator took a universal slice's CPU type from its FAT row, so a row
that called an x86_64 slice arm64 skipped that slice's Intel trailer and
let the arm64 payload stand for the whole image. Each slice's header is
now checked against its row with validateFatSliceIdentity. A mismatch
leaves the slice unread, so a universal image whose other slice confirms
Deno fails closed. The Intel fixture header now states
CPU_SUBTYPE_X86_64_ALL so its FAT rows can match it exactly.

* fix(deno): check the Intel trailer marker before judging its length

A trailer length word of 2^53 or more was dropped before its d3n0l4nd
marker was read, so an enclosing app with that length was skipped and a
nested app's range stood for the whole image. The marker is now read
first, and a marker-confirmed trailer whose length runs past the slice,
safe or not, joins the deferred truncated candidates and fails closed
unless an enclosing trailer holds it as data.

* fix(deno): count short ELF note tables against the note allowance

A note table shorter than one note header made a read of its trailing
bytes but counted no note, so many distinct tiny tables could force one
sequential read each past the 256-note allowance. Every nonempty table
now counts at least one entry, both in the up-front estimate and while
scanning, so an image past the allowance records the limit instead of
reading every table. The trailing-byte check moves into its own helper.

* fix(deno): fail closed on ELF extended section numbering beside a SUI note

A zero e_shnum with a nonzero e_shoff moves the section count into
section zero, so the section table was skipped and its SHT_NOTE tables
were never compared. Record it as damage, as PN_XNUM already is, so a
confirmed SUI note fails closed instead of reporting full coverage.

* fix(deno): keep undersized Intel trailers until enclosing ownership is known

A trailer length word below 8 was dropped before its d3n0l4nd marker was
read, so an enclosing app with a length of 0 to 7 was skipped and a nested
app's trailer was selected as the root. The marker is now read first, and a
marker-confirmed trailer too short to hold it is kept as malformed and fails
closed unless an enclosing trailer holds it as data.

* fix(pe): treat non-directory RT_RCDATA branches as unresolved

A duplicate typeId root entry whose target is a data entry was skipped
without marking the walk unresolved, so locatePeResourcePayloads returned
the readable named resource as complete. Route non-directory type
branches through the same unresolved path as unreadable names
directories so the Deno reader fails closed.

* fix(deno): fail closed on a zero-fill d3n0l4nd Mach-O section

denoSectionRange admitted the declared offset and size of a confirmed
__SUI,d3n0l4nd record without checking its section type, so a
S_ZEROFILL, S_GB_ZEROFILL or S_THREAD_LOCAL_ZEROFILL section could be
read as a file payload while MachoImage reports it as not file backed.
Reject zero-fill types with the shared isMachoZeroFillSection predicate
before assigning a physical range.

* fix(deno): bound the d3n0l4nd Mach-O section by its segment file extent

denoSectionRange checked a confirmed __SUI,d3n0l4nd record only against
the slice and file bounds, so a section reaching past its segment's
fileoff/filesize was still read as a complete payload while MachoImage
reports the same section as not file backed. Reject a section outside
its enclosing segment's file extent before admitting the physical range.

* style(deno): apply oxfmt to the DenoStandaloneLocation embedding union

* fix(artifacts): preserve Deno carrier ownership

* fix(artifacts): admit Deno parent segments

* fix(deno): preserve native segment ownership

* test(deno): cover mismatched Mach-O segment widths

---------

Co-authored-by: Matt Van Horn <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: morluto <[email protected]>
2026-11-09 21:43:01 +08:00
43f06eb1e8 feat(native): recover ELF function ranges from unwind tables (#9585)
* feat(native): recover ELF function ranges from unwind tables

inspect_elf_unwind_ranges and inspect-elf-unwind-ranges read .eh_frame
and .eh_frame_hdr from one local ELF32 or ELF64 image and list the
function ranges its FDEs name, with CIE facts, LSDA and personality,
the containing section and an exact symbol where one starts at the
address. Nothing is executed and no disassembler is needed. Pointer
encodings follow the DW_EH_PE rules with raw zero as null, discarded
FDEs are counted and skipped, the .eh_frame_hdr search table is
compared with the decoded FDEs, and record, row and symbol budgets are
bounded. verify:elf:unwind-ranges compares the reported starts with
llvm-dwarfdump or readelf on a compiled C++ program.

* fix(elf): keep unresolved unwind facts out of reported ranges

Skip FDEs whose initial location is indirect and do not locate
.eh_frame through an indirect eh_frame_ptr, since pointer slots are
not functions. Stop an unbounded header-located scan at a CIE with an
unrecognized augmentation, report ignored duplicate PT_GNU_EH_FRAME
headers as incomplete coverage, and accept a null personality stored
under an indirect encoding.

Keep only symbols at decoded FDE starts, cache name observations per
string-table offset, and decode names only for the returned page under
a fixed 16 MiB text allowance, so repeated or long names no longer
grow memory with the symbol count.

* fix(scripts): run the ELF unwind verifier under owned process trees

Launch probes, compiler drivers, the stripper, the frame dump and the
inspection through createVerifierCommands, as verify-binary-hardening
does, so a timeout or interrupt stops the whole tree. The temporary
directory is removed only after the owned commands have closed.

* docs(elf): move ELF unwind ranges guide under docs/guides/native

The documentation guide assigns analyst workflows to docs/guides/<domain>/.
Move the guide there, place its navigation and directory entries in the
Native binaries group, and update links from the docs index, CLI guide,
spec and authored skill. The public /elf-unwind-ranges route is unchanged.

* fix(elf): give unwind text limits their own recovery and skip indirect tables

Throw a dedicated failure when a page's symbol names exceed the 16 MiB
text allowance, and map it to a resource error that tells the caller
to request a smaller limit rather than raise max_ranges.

Read a CIE augmentation with one bounded NUL search and keep it as a
byte view, decoded only for returned CIEs, so a long augmentation is
never built up character by character.

Leave an .eh_frame_hdr search table with an indirect encoding unread:
the header is incomplete, the comparison is unavailable, and the table
no longer bounds a header-located .eh_frame scan.

* fix(elf): resolve header count and table forms and name IFUNC resolvers

Leave a non-zero .eh_frame_hdr FDE count under an indirect encoding
unresolved, since it is the address of a slot that is not followed, and
mark the header incomplete without reading the table.

Treat a DW_EH_PE_omit table encoding as an omitted search table before
testing the indirect bit, so a header that declares a count without a
table stays present with complete coverage, and accept that form in
output validation.

Match STT_GNU_IFUNC symbols at exact FDE starts after function symbols,
with a limitation that the name is the resolver, not the implementation
it selects at run time.

* fix(elf): require allocated unwind pointer bases

* fix(elf): map unwind header relative base

* fix(elf): validate unwind load mappings

* test(elf): cover mapped nonallocated frame agreement

---------

Co-authored-by: Matt Van Horn <[email protected]>
Co-authored-by: morluto <[email protected]>
2026-11-09 21:42:53 +08:00
f21fda0fc0 feat(elf): report a Linux kernel image's version banner and embedded build config (#9573)
* feat(elf): report a Linux kernel image's version banner and embedded build config

inspect_kernel_build_config and inspect-kernel-build-config read one
local vmlinux, raw arm64 Image, gzip bzImage or zImage, or configs.ko
and report its Linux version banner and the IKCONFIG .config embedded
between IKCFG_ST and IKCFG_ED, without executing it. A config is present
only when a gzip member ends exactly at IKCFG_ED, passes its CRC-32 and
ISIZE checks and parses as .config text; framing that fails is reported
malformed, never absent. bzImage gzip payloads are inflated within a
budget and other codecs are named as unsupported, using codec detection
now shared with the kernel module parser. The config search, inflate
sizes and option counts are bounded, scans honor cancellation, and
target-derived text is marked untrusted.

* fix(elf): reject a gzip member whose header checksum fails

When FHCRC is set, compare the low 16 bits of the header CRC-32 before
inflating, so a damaged header no longer yields a present config or an
inflated bzImage payload.

* fix(elf): detect the bzImage codec inside the declared payload

Codec detection now reads the same payload_offset/payload_length slice that
is inflated, so bytes past a short payload cannot name its codec.

* fix(elf): report a framed config that does not decode as malformed

A damaged or cut-off deflate stream between IKCFG_ST and IKCFG_ED was
skipped and could end as an absent config with complete coverage. It is
now malformed with config_gzip_invalid, and a later valid config still wins.

* fix(elf): scan config lines in place and accept long string values

Config text is read one line at a time instead of split into an array, and
a quoted value is validated before it is decoded once. The 4096-character
string cap is removed: Kconfig has no such limit and max_config_bytes
already bounds every line, so a long CONFIG_EXTRA_FIRMWARE list is no
longer reported as malformed.

* fix(elf): let a live cancellation reach the kernel config parser

The parser ran synchronously, so an abort raised during parsing could not
change the signal before it returned. Inflation now runs on the zlib thread
pool and each scan yields to the event loop once per MiB, so the existing
cancellation checks observe a real abort.

* refactor(elf): carry the refused kernel config budget as a typed fact

Budget failures are now KernelBuildConfigBudgetFailure with a knob field,
and the provider builds its recovery advice from that field instead of
searching the diagnostic message for an option name.

* docs(elf): move the kernel build config guide under docs/guides/native

The documentation guide assigns analyst workflows to docs/guides/<domain>/.
Move the guide there, place its navigation and directory entries in the
Native binaries group, and update links from the docs index, CLI guide,
spec and authored skill. The public /kernel-build-config route is unchanged.

* fix(elf): yield while checking one long config line

A config made of one long quoted value never reached the per-line yield, so
the control-byte check, value validation and SHA-256 ran in one synchronous
block. Each now works one MiB window per event-loop turn, and the line
patterns match only a bounded name prefix instead of the whole value.

* fix(elf): return paged config entries that do not pin the decoded text

Entry names and values were V8 slices of the whole decoded config, so a
one-entry page kept the full text alive. Entries in the returned page are
now standalone copies, so retained memory follows the page size.

* fix(elf): yield while kernel marker searches find nothing

IKCFG_ST, IKCFG_ED and banner searches used one Buffer.indexOf over the
rest of the image, so a large image with no marker never yielded. They now
search overlapping one MiB windows and yield after each window without a
match.

* fix(elf): preserve long kernel config names

* fix(elf): frame kernel configs by gzip member boundaries

---------

Co-authored-by: Matt Van Horn <[email protected]>
Co-authored-by: morluto <[email protected]>
2026-11-09 21:41:56 +08:00
morluto 7b9b6cc78b fix(electron): preserve unknown indirect listener ownership (#9653)
* test(javascript): distinguish package scope in route fixtures

* test(apple): separate identity and refusal fixture groups

* fix(electron): preserve uncertainty in indirect listener ownership
2026-11-09 08:39:31 -05:00
morluto b1f473fcf8 docs: clarify publication recovery and Evidence ownership (#9654) 2026-11-09 08:39:20 -05:00
morlutoandhhang 24053f7ee2 fix(desktop): preserve escaped xprop text (#9652)
* fix(desktop): preserve xprop escaped window text

* test(mcp): cover source fitting and omitted delivery budgets

* test(javascript): distinguish package scope in route fixtures

* test(apple): separate identity and refusal fixture groups

---------

Co-authored-by: hhang <[email protected]>
2026-11-09 08:35:55 -05:00
morluto a344650a7b fix(artifacts): preserve bundle and extraction failures on abort (#9649)
* fix(dotnet): preserve read failures during cancellation

* refactor(artifacts): reuse chunk cancellation owner

* fix(artifacts): retain extraction source lookup failure
2026-11-09 08:14:02 -05:00
morluto 9e0bc71e78 fix(comparison): retain integrity conflicts for duplicate paths (#9647)
fix: retain integrity conflicts for duplicate artifact paths
2026-11-09 08:12:55 -05:00
1f9bf8af0e fix(providers): mark callee coverage partial at computed call sites (#8340)
* fix(call-path): keep computed-call targets out of complete callee coverage

Ghidra reported complete callee coverage when a computed call had one
ReferenceManager target, so trace_call_path, build_call_path and the
function comparisons turned the static candidate into a definite negative.
The bridge now keeps those targets as observed callees and marks callee
coverage partial, naming the computed call sites. IDA callee reads cannot
classify their call sites, so their callee coverage is partial too. The
Ghidra call-coverage profile revision refuses older snapshots.

A source-owned x86-64 bridge probe in the ghidra-bridge-sources job checks
the slot, register and direct-call controls against real Ghidra.

Fixes #8277

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(ci): match the observed call coverage probe marker

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: morluto <[email protected]>
2026-11-09 21:03:14 +08:00
morluto 419956f56e fix(apple): preserve unknown identity in IPS joins (#9643)
* fix: preserve unknown identity in Apple IPS joins

* fix: require known CPU identity for Apple IPS joins

* refactor: centralize x86 Mach-O subtype identity

* docs(apple): explain unknown join identities

* fix(apple): bound architecture aliases to map entries
2026-11-09 21:02:08 +08:00
morlutoandSonai Biswas c5ee066022 fix(process): preserve semantic comparison across capture-local timing (#9644)
fix(process): stabilize capture comparisons

Co-authored-by: Sonai Biswas <[email protected]>
2026-11-09 21:02:03 +08:00
3230f50b16 feat(sqlite)!: page selected rows with a stated order and row offset (#9331)
* feat(sqlite): page selected rows with a stated order and row offset

readRows read `NOT INDEXED LIMIT ?` with no ORDER BY and reported
order: "unspecified", so an agent could not reach rows past row_limit
deterministically: raising row_limit hits the fixed 16 MiB reply budget,
and the sampled order depends on whichever index SQLite happened to scan.

Read the window in a unique, stated order and expose the position:

- rowid tables order by rowid unless all of rowid, _rowid_ and oid are
  declared columns, in which case the order stays unspecified.
- WITHOUT ROWID tables order by the primary-key columns, reusing each
  key's DESC flag and declared collation from pragma_index_xinfo so the
  plan keeps index order instead of materialising a sorter.
- rows.order, rows.row_offset and rows.next_row_offset report the window;
  next_row_offset is null once the window reaches the end.
- row_offset (CLI --row-offset) requires table and defaults to 0. A
  non-zero offset is refused when the table declares no usable order,
  because the skipped prefix would be arbitrary.

The schema now checks next_row_offset against truncated and the offset so
a worker reply cannot claim a page it did not read.

One attribution fix came with it: adding ORDER BY text can push an
over-wide projection past SQLite's SQL-text limit, which fails as
SQLITE_TOOBIG before the result-column limit is reported. Attribute that
case to column capacity too, so a 250k-column request still reads as
capacity rather than a byte budget.

Verified: npm run check:fast, npm run format:check on the touched files,
npm run verify:module-boundaries, npm run docs:check, and 196 tests
across the sqlite boundary, application and CLI/MCP suites. A 1002-row
inspection and in-memory EXPLAIN QUERY PLAN checks confirmed the
WITHOUT ROWID path adds no sorter. Full check:pr and the complete test
suite were not run.

* fix(sqlite): resolve the rowid alias and keep paging claims reachable

Three defects in the row paging added alongside row_offset:

- readRowOrder emitted ORDER BY rowid for every rowid table, but a table
  that declares a rowid column shadows that spelling, so the sort used the
  stored column and could repeat or drop rows across pages. Order now names
  the first alias the table leaves unbound, read from raw name bytes so an
  unrelated malformed identifier is not decoded just to choose an order.

- The inventory projection could hide the primary key a WITHOUT ROWID table
  orders by, silently degrading a paginated read to unspecified order. The
  order key is now read from the table itself rather than from the columns
  the caller asked to see.

- A truncated table with no stated order reported a next_row_offset that the
  row_offset rule then refused. It is null there, and the reply limitation
  no longer claims an unspecified order for windows that have one.

rowEvaluationFailure also probed the first rows of the table instead of the
requested window, so a failure confined to a later page was attributed to
columns that evaluate fine there.

* test(sqlite): assert the concatenated pages

The paging regression checked only counts, offsets and flags, so a second
page that repeated the first page's rows would still pass. Assert the values
read across all three pages instead.

* fix(sqlite): decode row keys in the database encoding

readRowKeyFacts decoded primary-key names as UTF-8 and probed a fixed
hidden set, so two supported schemas could not be paged at all:

- A UTF-16 database stores key names as UTF-16 bytes, so "k" decoded to
  NUL-padded text and ORDER BY named an identifier that does not exist.
  Pass the detected encoding, as readColumns and the index-metadata path
  already do.
- A virtual generated column named rowid (hidden=2) was absent from the
  shadow check, so ORDER BY rowid evaluated the generated expression
  instead of the rowid and could sort non-uniquely or fail outright.
  Include generated columns in the alias probe.

Also stop decoding primary-key names for rowid tables: their ORDER BY
names an alias, never a declared key, so an unselected malformed key
name could abort an otherwise readable selection.

The page-concatenation assertion now narrows SqliteValue before reading
.value, which the null/blob arms do not carry; this was failing the
Static checks typecheck job.

* fix(sqlite): order WITHOUT ROWID rows by the index's own key sequence

`readRowOrder` filed `pragma_index_xinfo` key terms into a map keyed by
column name, so a valid composite key that repeats a column —
`PRIMARY KEY(a COLLATE BINARY, a COLLATE NOCASE DESC)` — collapsed to one
term. The generated clause then overstated uniqueness: it omitted the
BINARY term, so `A`/`a` ties survived, and the `row_offset` paging
advertised a `primary_key` order that the actual key does not establish.

Build the terms from the index rows in `seqno` order instead, keeping
repetitions, and bail to `unspecified` if any declared key column never
appears in the index. The declared collation stays explicit so a caller
column's own collation cannot re-sort the window.

Verified against a real SQLite database that the repeated key is accepted
and that the old clause orders A, a, B while the index orders A, B, a.

* fix(sqlite): accept a null next offset on unordered truncated rows

readRows already withholds next_row_offset when a table shadows rowid, _rowid_ and oid and declares no primary key, because every non-zero offset is refused there. The reply schema still required the offset whenever truncated was set, so the provider rejected its own worker result and the first sample never reached CLI or MCP. Require the offset only when the order is stated.

* fix(sqlite): probe row keys only for ordinary tables and name row_offset

readRowKeyFacts ran for a selected virtual shadow table before readRows
could reject it, so an unavailable module surfaced as SQLite's
"no such module" instead of the selection refusal. Probe the key only
when the selected kind is an ordinary table and leave the order
unspecified otherwise, since no rows are read for that kind.

The unordered-offset refusal also reported the generic selection reason,
which callers see against table. Give it its own reason so the failure is
attributed to row_offset.

* feat(sqlite)!: page selected rows with a stated order and row offset

Selected-row inspection currently reports only rows.order: "unspecified" and
offers no way to reach rows past the first sample deterministically. Main also
refuses non-zero row_offset today, so nothing relies on that omission; this
change makes the stated order and the offset the contract, reports the next
offset the caller feeds back, and keeps the existing byte, heap, statement and
deadline limits.

BREAKING CHANGE: rows.order becomes rowid | primary_key | unspecified, and
rows gains required row_offset and next_row_offset members. A client that
validates selected-table output against the previous schema (where order was
the only permitted value) rejects a now-valid reply. Migration: accept the two
new members and treat order: "rowid" | "primary_key" as the stated order the
offset applies to; a null next_row_offset means the window reached the end.

* docs(sqlite): say a null next offset also means no stated order

The selected-rows limitation described next_row_offset as null only when the window reached the end. An unordered table whose row_limit truncates the sample also publishes null, because an offset there would name a request the row-offset rule refuses, so the Evidence read as if the sample were complete. State the second cause and pin it in the existing regression.

* test(sqlite): drop the limitation wording assertion and state the unordered exception

The boundary test pinned the sentence a caller reads in `limitations`,
so a harmless rewrite of that text failed a paging test whose real
subject is `order`, `truncated` and `next_row_offset`.
docs/development/testing.md asks for facts over frozen explanatory prose,
and the three structured expectations already fail if the paging fact
changes.

The tool contract promised that retained rows always have a unique order
and can be paged. A rowid table that shadows rowid, _rowid_ and oid and
declares no primary key has no such order: it returns
order=unspecified with a null next offset and refuses a non-zero
row_offset. Say so in the description so callers do not plan a
continuation the tool always refuses.

* docs(sqlite): say unordered tables cannot be paged

The description told callers that a truncated table without a stated order
needs "the table read without offsets", but omitting row_offset starts at
zero again: with an unchanged row_limit the next call repeats the first
sample instead of continuing past it. Say that these tables cannot be
paged and point at row_limit for a larger first sample.

* style(cli): wrap the native data type path description

The `inspect-native-data-type` argument description line is 82 columns, over the repository's 80-column `.oxfmtrc.json` limit, so `npm run format:check` fails on main and on every branch merged from it. It came in with #9465 and the following commits to this file did not touch it. Reformat the one call the formatter objects to; no behaviour change.

* fix(sqlite): bound rowid alias comparison by name byte length

readRowKeyFacts decoded every column name before testing it against three short aliases, so a table declaring a multi-megabyte name could exhaust the worker heap even when the caller projected the column away. Reject names that cannot be an alias by their byte length, accounting for the database encoding, before building any string.

---------

Co-authored-by: 2SinceJuly <[email protected]>
Co-authored-by: morluto <[email protected]>
2026-11-09 21:01:58 +08:00
Chiragandmorluto 0a15246d32 docs(mcp): name the accepted seed kinds on trace_application_feature (#8220)
* docs(mcp): name the accepted seed kinds on trace_application_feature

The compact input profile reduces this schema to shallow properties, which
drops the seed union and its kind enums, so agents could not see which
kinds a seed accepts without reading the source. Describe the seed field
with its kinds, match defaults and one example; shallow reduction keeps
per-property descriptions, so the guidance survives the compact profile.

Closes #8205

* test(mcp): isolate seed guidance catalog configuration

---------

Co-authored-by: morluto <[email protected]>
2026-11-09 21:01:52 +08:00
9108d9a627 fix(javascript): keep strict module checks unproven when alias walks exhaust their budget (#9387)
* fix(javascript): keep strict module checks unproven when alias walks exhaust their budget

Fixes #8201.

* fix(javascript): examine queued module sources after a strict walk exhausts its budget

A strict check that exhausts the alias budget stopped the whole walk, so a module branch queued beside the growing alias was never examined. Stop expanding instead, and drain the queued sources.

* fix(javascript): drain exhausted strict walks by selected keys and finite expressions

After exhaustion the limiter widens every key, so draining by normalized paths could match process.foo as mainModule. Keep each queued source's selected keys, expand finite expressions such as sequences and conditionals, and stop only at bindings and calls.

* fix(javascript): follow bindings and calls breadth first in exhausted strict walks

An exhausted strict walk skipped every binding and call, so (flag ? m : r).require with const m = module lost the module branch when r was explored first. Drain the queue breadth first after exhaustion and follow bindings and calls under a second alias selection budget, so a growing alias cannot starve a sibling.

* fix(javascript): bound every state a strict walk creates after exhaustion

After the alias budget is exhausted, paths are no longer normalized, so a
cycle through containers or getters can keep growing its selected path
without crossing a binding or call. Count each new state against the
drain budget instead of only binding and call follow-ups.

* fix(javascript): retain uncertainty at alias cutoff

---------

Co-authored-by: Matt Van Horn <[email protected]>
Co-authored-by: morluto <[email protected]>
2026-11-09 07:59:15 -05:00
morluto 3c3d405c00 fix(artifacts): preserve physical failures during cancellation (#9641)
* fix(ines): preserve physical read failures on cancellation

* fix(artifacts): preserve root identity failures on cancellation

* refactor(artifacts): reuse cancellation projection
2026-11-09 20:56:15 +08:00
morluto 43d9c9d19b fix(uimage): reject impossible component extents before capacity (#9640)
* fix(artifacts): validate uImage extents before count limit

* docs(testing): distinguish malformed and capacity controls
2026-11-09 20:56:10 +08:00
morluto 86059108b1 fix(artifacts): retry cancelled reader preparation (#9639) 2026-11-09 20:56:05 +08:00
morluto 35fbec9df5 fix(artifacts): validate Godot row extent before budget (#9638) 2026-11-09 20:56:01 +08:00
morluto b394d50943 fix(reconstruction): honor resolved unknown revisions (#9637) 2026-11-09 20:55:57 +08:00
morluto 694edef951 fix(decompile): retain published output receipts (#9633)
* fix(decompile): retain published index on failure

* fix(decompile): preserve publication failure facts

* docs(decompile): explain retained publication receipts

* fix(decompile): retain receipts across provider cleanup chains

* fix(evidence): retain diagnostics through cleanup primary chains

* refactor(evidence): retain receipts once on the returned error
2026-11-09 20:55:53 +08:00
morluto d4b9a33348 fix(native): disclose failed accessibility reads (#9632)
* fix(native): disclose unavailable accessibility actions

* fix(native): retain accessibility attribute failures

* fix(native): preserve unknown accessibility selection
2026-11-09 20:55:48 +08:00
morluto b06df804d6 fix(model): validate GGUF extents before capacity (#9631)
* fix(model): validate GGUF extents before capacity

* fix(model): validate raw extents before capacity admission
2026-11-09 20:55:44 +08:00
df2d018b30 feat(desktop): read gzip documents as the document inside (#9111)
* fix(desktop): release a capture when its start is cancelled after launch

Cancelling start_build_capture during the opened app's screenshot left
the capture running, so the next start was refused. The capture is now
kept for the owner's cleanup, and the next start stops it first.

* fix(desktop): keep a published witness error and tag an app data refusal

A second failure to close a published witness returns the original error,
so its record and cleanup lease stay bound. A reset the app itself
refuses is an AppDataRefusal; only a reply that is not that refusal stays
unsettled. A missing child of a cut view is undecided with the same
description in both evaluators, and the shared cases cover it.

* fix(desktop): align a cut view's missing text with the Python check

A missing child of a truncated view is undecided for the same sentence in both evaluators, including the pointer the view does not contain.

* fix(desktop): keep one published witness cleanup across retries

A published record and its bound cleanup error stay together. A later close failure returns that error, and the unused path that built a fresh adapter error is gone.

* fix(desktop): keep a bundle task read inside the witness result

A cancelled, refused, or failed read of the bundle's task files returns the witness's Result, including a cleanup lease when a handle would not close.

* test(desktop): pass the settle timing when reading a witness bundle

The witness takes the settle timing before the bundle path, so the bundle-read tests keep the path in its own argument.

* fix(desktop): bound a guest file answer and split a long controller argument

A data/get whose base64 answer would exceed a quarter of the V8 heap is refused before it is read. Controller JSON that exceeds Linux's single-argument limit travels as several arguments the controller joins.

* fix(desktop): keep an underreported guest file from raising its read

A data/get answer is admitted only when its base64 body fits in the heap quarter after the copies held during parse. Decoded bytes larger than the computer reported are dropped.

* fix(desktop): grade shipped seeds and keep selected settings and sqlite logs

Seed checks follow the files the bundle ships, so an omitted lock is absent. An incomplete checkpoint is not reported as no change. A selected link keeps its spelling, and a database's wal and journal stay supporting state. Closing the fake computer stops a detached capture.

* fix(desktop): keep added-record checks off ids, dates, and joined timestamps

A position-named record's fields keep their paths, so an identifier, a stamped date, and text past the limit are not suggested checks. A whole-text check does not climb into an ancestor whose text joins a timestamp.

* fix(desktop): bound home fetches and keep unsettled edits readable

Split home-folder reads by the guest answer budget, keep a capacity error
from the capture output, and drop the superseded task-argument refusal.
Grade kept text per line, leave unretained dconf unread, and reserve
by-position notes for XML children. Map a linked database's sidecars
through the selected spelling and stop a detached capture only when its
start identity still owns the pid.

* fix(desktop): describe unretained dconf as unread

The key comparison treats a missing copy as unknown. The comment still
said that copy counted as an empty key list.

* test(desktop): keep a capture capacity error through endedCapture

An output past the guest answer ceiling stays the resource constraint,
with its heap recovery and non-retryable status, instead of a generic
capture-exit message.

* fix(desktop): keep nested save times and formatting runs out of checks

A field check drops save-time leaves before it joins the field, so a nested
timestamp is not part of the suggested text. A text check beside a save time
uses the paragraph when the diff names a formatting run.

* test(desktop): read paragraph pointers from checks that have them

* test(desktop): expect a large task to export intact

The 96 KiB refusal is gone. A prompt past that size reaches the computer
and comes back unchanged, instead of failing before export.

* fix(desktop): keep real edits that save-side heuristics were dropping

Repeated unnamed fields stay content checks. A formula that still has
text is not renumbered with its ExprID. One gained style attribute is
the edit; a repeated fill-in stays upkeep. Phone numbers and plain
clock times stay text, and a decimal is the element's whole text. An
older verifier matches on the task it states, not its evaluator source.

* fix(desktop): cover repeated records and keep timestamps out of checks

An added record whose words are already in the seed still gets the list's
text when that text fits. Readiness is a start reason, so a final check
names seed locks without matching the message. Field text split by a
timestamp stays separate, and a timestamp line is not offered as a guard.

* fix(desktop): compare a cell's joined decimal within tolerance

The whole-element check keeps numeric tolerance, so 437.80 and a long
float still match 437.8, including when a run splits the digits. A
different number or other text does not. Both evaluators read an
element's text for that comparison.

* fix(desktop): grade a number from a complete XML element only

A tolerance check joins an element's text only in an XML file or an XML
archive entry, and leaves that check undecided when the view is cut, so a
dropped descendant cannot turn the kept runs into a passing number. A JSON
object with the same shape stays the value itself. Equivalent decimals and a
split run on a whole cell still match.

* fix(desktop): accept an older grader only when its index helper agrees

The witness still matches a bundle whose evaluator is this REA's, or the older
index expression alone when no path segment is a leading-zero number. A
truncated verifier, a changed grader, or that older helper beside a segment
such as 01 no longer counts as the same task.

* fix(desktop): require the added record and leave save times out of list checks

A record a selector names is checked itself, so its words have to be in that
record. When an unnamed record only repeats words the seed already has, a
list that holds a save time is checked by the text around that time. A later
save of the same records still passes, and a missing or rewritten record fails.

* fix(desktop): judge the older index helper by pointer segments only

A leading zero in a file name or a URL does not change how the older index
helper reads a pointer. The witness still rejects that helper when a pointer
segment is a number such as 01.

* fix(desktop): do not suggest list text the seed already passes

A repeated record is shown by text the seed does not hold. The seed's own
text is not a check. A pointer inside a check value is not a pointer segment
for the older index helper.

* fix(desktop): keep a linked settings file in the folder the link points at

A selected ~/.config alias no longer moves MuseScore settings to that alias.
The seed keeps settings/MuseScore or Documents, which is the path the export
opens the note from.

* fix(desktop): split home fetches by answer size and keep a size refusal

A batch of tiny files stops before each path's envelope exceeds the host
answer budget. A capture output past that ceiling stays a resource error
instead of becoming a generic exit.

* fix(desktop): seed a selected link under the path the app uses

The selected spelling wins, so ~/.config/MuseScore is not rewritten to the
folder it points at and the note stays the one launched document. A database
wal and journal follow that database. A launch argument is respelled the same
way. Teardown signals a detached PID only when its start identity still matches.

* fix(desktop): keep a witness's actions and an incomplete checkpoint

A failed witness save retries the action log it first recorded. A deletion
left unconfirmed between the seed and the end is not reported as no change.
Windows packs npm through a shell, which can start npm.cmd.

* fix(desktop): read verifier pointers from the parsed checks

A brace inside a check value is not an object boundary. A leading-zero
pointer after that value still rejects the older index helper.

* fix(desktop): prefer the most specific home spelling and retarget launch files

A selected parent directory no longer hides a settings folder walked through
a link. A launch filename under that folder is replaced with the seeded
file's absolute path.

* fix(desktop): pack the build runtime through npm's JavaScript entry

npm pack and npm ci no longer spawn npm.cmd through a shell, so a temporary
directory whose path contains spaces stays one argument.

* fix(desktop): spell launch settings and keep a database log exact

A database log matches only that file, so a neighboring folder is not moved.
A launch option and the working directory use the same home spelling as the seed.

* fix(desktop): move a state database's logs with the database

The write-ahead log and journal follow the spelling the database received,
including a walked state link. A neighboring folder stays put. A separate
--config argument uses that spelling too.

* fix(desktop): keep a selected file ahead of a database-log guess

A file selected as itself keeps that spelling even when its name ends in
-journal. Relative launch arguments are resolved in the captured working
directory before that directory moves.

* fix(desktop): keep outside-home database logs and option values

A selected database outside the home keeps its write-ahead log. Launch
options are rewritten only when they name a captured file or settings path.

* fix(desktop): follow a database mapping and own limitation text

A selected database keeps its log when a parent folder moves or the file
sits outside the home. Trash and seed-lock tests compare the owning notice
with the paths, and launch options that are not captured paths stay as written.

* fix(desktop): retarget a settings folder that holds captured files

A nested profile directory is a captured path when a seeded file is inside
it. An option value that only resolves under the home stays as written.

* fix(desktop): keep a program word and a directory's neighbor

The program after env stays the program even when a captured file sits in a
folder of that name. A selected directory is not a database, so a neighboring
file keeps the parent folder's spelling.

* fix(desktop): record whether a selected path is a directory

Capture stores the walked path's kind. A neighboring file of a selected
directory keeps the parent folder's spelling even when that directory never
changes and its children are not content roots.

* fix(desktop): mark containing paths without a pairwise scan

A recorded path marks its known ancestors as directories in one walk up
the path, instead of comparing every recorded path with every other.

* fix(desktop): keep a selected folder that is named like a database log

A folder the caller selected stays a selected root when its name ends in
-journal or -wal. A generated log beside a database file still does not.

* fix(desktop): refuse a build command that exceeds the argument vector

Splitting one argument still leaves the whole command under Linux's E2BIG
limit. A request past that budget is refused before the process starts.

* fix(desktop): remap a captured path in an env assignment

The program word stays the program. A NAME=value assignment keeps its name
and follows a captured path value when that path's spelling moves.

* fix(desktop): keep oversized text out of draft guards

A value or line longer than the draft's text bound is not copied into a
guard, so one large frame cannot fill the task by itself.

* fix(desktop): keep an empty env value empty

An empty assignment is not a path. Resolving it named the working directory
and rewrote the value when that directory's spelling moved.

* fix(desktop): check build runtime export capability

* fix(desktop): provide complete runtime repack command

* fix(desktop): retain runtime probe failures

* test(desktop): identify capture independently of schema preflight

* fix(desktop): preserve document URLs and value formats

* fix(desktop): bound added checks and omit noisy text guards

* fix(desktop): preserve launch URLs and JSON draft values

* fix(desktop): recognize captured file URL documents

* fix(desktop): render captured file URLs for runtime home

* fix(desktop): distinguish phone numbers from save metadata

* fix(desktop): preserve launch URLs and user text

* fix(desktop): preserve local file URL authority

* fix(desktop): preserve local file URL authority

* fix(desktop): render captured file URLs at launch

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): classify numeric timestamps using field context

* fix(desktop): retain context for generated draft values

* fix(desktop): retain context for generated draft values

* test(desktop): cover generated IDs in text guards

* test(desktop): cover generated IDs in text guards

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): isolate launcher URL encoding

* fix(desktop): retain clean text in noisy record fields

* style(desktop): format the noisy-record draft files with the pinned oxfmt

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* test(desktop): move launch execution to boundary suite

* fix(desktop): redact build schema failure output

* refactor(desktop): normalize schema failure once

* fix(desktop): omit unsafe schema parser snippets

* fix(desktop): preserve draft change and selected path evidence

* test(desktop): group retained dconf note regressions

* fix(desktop): respect archive entry format in draft checks

* test(desktop): separate unowned-file draft note cases

* docs(desktop): clarify task checks before scratch export

* fix(desktop): respell selected paths in file URLs

* test(desktop): group captured document spelling cases

* fix(desktop): bound draft preview serialization

* fix(desktop): restore selected state aliases

* fix(desktop): respect entry format in draft noise

* test(desktop): match exported alias evidence at its JSON boundary

* style: fix desktop launch test formatting

* style: format native command path schema

* fix(desktop): map selected external launch paths

* style(desktop): format seed document regressions

* test(desktop): group launch URL regressions

* fix(desktop): omit redundant nested state aliases

* fix(desktop): compare added free text as a whole

* fix(desktop): check recompressed seeds as shipped

* fix(desktop): map captured launch paths once

* refactor: remove unused whole-text guard state

* refactor: stop passing unused text children

* test: align free-text checks with whole-note policy

* fix: validate recompressed desktop archive seeds

* style(desktop): format archive seed regression

* fix(desktop): redact runtime schema errors

* fix(desktop): normalize captured file URLs

* fix(desktop): report seeded files by capture path

* fix(desktop): retain startup readiness failure stage

* fix(desktop): retain JSON date checks

* fix(desktop): preserve archive formatting checks

* fix(desktop): preserve explicitly selected journal files

* fix(desktop): report build command transport limits

* style(desktop): format capture review fixes

---------

Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: morluto <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-09 20:48:08 +08:00
6c1faaed75 fix(analysis): order graph depths numerically (#8268)
Co-authored-by: juncheng.ye <[email protected]>
Co-authored-by: morluto <[email protected]>
2026-11-09 20:28:46 +08:00
1fcf50518e fix(native): wrap the legacy rebase cursor at 64 bits like dyld (#8111)
dyld keeps the LC_DYLD_INFO rebase cursor in a uint64_t, so an
ADD_ADDR_ULEB, DO_REBASE_ADD_ADDR_ULEB or single-slot skip operand above
2^63 steps backward. REA tracked the cursor as an unbounded bigint, so the
same stream overflowed past 2^64, failed as "Rebase expansion leaves its
file-backed segment" and left every later slot unknown. The bind stream
already wraps the same way since 576b58cef.

Every advance now wraps at 64 bits. addRun still bounds each emitted slot
to its segment, so a wrapped cursor outside the segment and multi-slot
runs with a backward skip remain refused.

Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: morluto <[email protected]>
2026-11-09 20:28:42 +08:00
morluto 437e65d349 fix(unity): validate directory extent before capacity (#9635) 2026-11-09 20:28:38 +08:00
morluto df5103e26d fix(artifacts): validate SEA table extents before limits (#9634) 2026-11-09 20:28:34 +08:00
morluto f328b49d22 fix(cli): retain desktop directory selection (#9627) 2026-11-09 20:28:29 +08:00
morluto 70e4653feb fix(setup): retain verified skill installation outcome (#9630)
* fix(setup): retain verified skill installation outcome

* fix(setup): settle skill cleanup after host close
2026-11-09 20:28:25 +08:00
morluto 1883578b67 fix(evidence): preserve unknown source closure (#9629) 2026-11-09 20:28:21 +08:00
97b5503f39 feat(apple): join IPS images to admitted Mach-O slices (#9570)
* feat(apple): join Apple IPS frames to a selected Mach-O or dSYM slice

inspect_apple_ips reported every image UUID as unknown and stated that joined
frames were unobserved. Accept an optional join_path, read its LC_UUID and
__TEXT vmaddr with the existing bounded stable-artifact reader, and match by
canonical UUID plus architecture.

A frame joins only when exactly one slice carries the image UUID and an
agreeing architecture, so arm64 and arm64e never cross, all-zero UUIDs never
join, and a conflicted or unreadable artifact stays typed instead of guessed.
Joined frames report the slice __TEXT vmaddr plus the recorded imageOffset as
a static address, which is the value atos resolves for the same report.
Symbolication is still not performed.

* refactor(apple): remove superseded join integer type import

* fix(apple): share FAT admission and preserve completed join facts

* fix(apple): bind standalone joins to admitted source identity

---------

Co-authored-by: 2SinceJuly <[email protected]>
Co-authored-by: morluto <[email protected]>
2026-11-09 20:20:33 +08:00
Matt Van HornandMatt Van Horn 645735fc0f feat(windows): inspect Shell Link (.lnk) shortcut files (#7859)
* feat(windows): inspect Shell Link (.lnk) shortcut files

Add inspect_windows_shortcut / inspect-windows-shortcut to read one
local Shell Link without resolving or executing the target. The report
keeps header flags and FILETIMEs, IDList items, LinkInfo volume and
network names, StringData, ExtraData including Tracker droid facts
labelled derived, and derived observations such as argument length
and a minimized ShowCommand.

* fix(windows): tighten Shell Link string reads and coverage

- Decode counted StringData over its full CountCharacters payload.
- Locate LinkInfo string terminators before charging max_string_bytes
  and before decoding; an unterminated string is a coverage issue.
- Mark an IDList without a TerminalID and an out-of-range
  LinkInfoHeaderSize as partial coverage.
- Report arguments_present and argument_length as null when
  HasArguments is set but the field could not be read.
- Derive target_extension from the joined base path and suffix.
- Keep ISO dates for FILETIME and UUIDv1 timestamps before 1970.
- Retain the completed file snapshot on parse failures.
- Reject an empty CLI path before normalization.
- Select the shortcut contract from its family in focused tests.
- Fixture StringData no longer writes a NUL into the counted payload.

* style: format docs index and Shell Link boundary type

Apply oxfmt to the two files format:check reports so Static checks passes.

* fix(windows): reject network share paths for Shell Link reads

inspect_windows_shortcut is advertised as offline, but the Windows path
schema admits UNC paths, and lstat on one can contact an SMB server and
offer the caller's credentials.

Reject UNC, extended UNC, and other host-prefixed device paths in the
provider before any filesystem call. Extended drive paths such as
\\?\C:\x stay allowed. A mapped network drive cannot be told from a
local drive by its path, and the docs say so.

* fix(windows): decode Unicode Shell Link file-entry names

File-entry items with bit 0x04 of the type byte, such as 0x36, store a
UTF-16LE name, but the parser always read it as Latin-1. The read stopped
at the first zero byte, so report.exe became r and an IDList-only
shortcut reported the wrong target_extension. Read those names as
UTF-16LE.

* fix(windows): read volume labels by exact Shell Link discriminator

VolumeLabelOffset 0x14 selects VolumeLabelOffsetUnicode and is not itself a
label offset, and that Unicode field exists for no other value. The parser
treated any offset of 0x14 or more as having both, so a Unicode-only label such
as "OS" also produced a false ANSI label "O", and an ANSI label stored past 0x14
had its own bytes read as a Unicode offset.

Branch on the exact value in parseVolume, the one place that interprets it, and
report a VolumeID too short to hold the selected field. The fixture wrote both
encodings for a Unicode volume, which hid the false label, so it now writes one.

* fix(windows): limit network share rejection to Windows hosts

POSIX hosts read repeated leading slashes as one local root, so an
accepted selection such as ///tmp/shortcut.lnk is a local file there.
Apply the host-prefixed path check only on Windows, and take the
platform through the provider constructor so the Windows path forms
stay covered on every test host.

* fix(windows): compare shortcut icons only against full paths

A stored IDList filename or relative path cannot show that an icon at a
full path is elsewhere, so the comparison reported a false difference.
Report null unless the icon and a recorded target are both full paths,
and assert the missing TerminalID issue by code and offset instead of
its message.

* fix(windows): keep unread ExtraData blocks unknown

A walk that stopped before or inside ExtraData still reported the blocks
that HasExpString and HasExpIcon expect as absent, though they were never
checked for. Report a block as absent only after the TerminalBlock shows the
section was read in full. Without one the block stays unknown and coverage
stays partial.

* fix(native): ignore LNK network provider type unless ValidNetType is set

CommonNetworkRelativeLink NetworkProviderType is only meaningful when the
ValidNetType flag (0x2) is set. Return null otherwise.

* fix(native): accept any ExtraData TerminalSize below 4 as the terminal

MS-SHLLINK requires TerminalSize to be less than 4, not exactly 0. Treat
1, 2 and 3 as the terminal block instead of a malformed block.

* fix(native): derive shortcut target facts from the stored environment target

Include the EnvironmentVariableDataBlock literal target among the target
candidates for target_extension and the icon comparison. Variables are not
expanded and the target is not opened.

* fix(windows-shortcut): keep unexpanded variable paths unresolved in icon comparison

A stored environment target such as C:\Users\%USERNAME%\app.exe could be
compared as different from C:\Users\Alice\app.exe. Variable-bearing paths
are never expanded, so the icon comparison now returns null unless a fixed
target matches the icon exactly.

* test: drop redundant ok assertion before typed error guard

The testing guide asks for the typed error to be thrown before asserting a
successful Result value, and says a preceding .ok assertion adds no coverage.

* fix(windows): point out-of-range LinkInfo offsets at their field

A LinkInfo, VolumeID or CommonNetworkRelativeLink offset that points
past its structure was reported at base + offset. With an offset such
as 0xffffffff that position exceeds uint32, so the report failed its
schema and the service discarded the whole partial result.

Report such issues at the offending offset field instead, which keeps
every issue offset and coverage.failing_offset inside the file. Cover
each LinkInfo offset field in the parser tests and the
LocalBasePathOffset case through the stable filesystem service.

* fix(windows): require RFC 4122 variant before deriving Tracker UUID facts

A version nibble of 1 alone does not identify a version-1 UUID. Also require the clock_seq_hi_and_reserved top bits to be 10, so other GUID layouts keep their raw value and derive no MAC or timestamp.

* fix(windows): ignore DeviceNameOffset fields unless ValidDevice is set

MS-SHLLINK 2.3.2 says DeviceNameOffset and DeviceNameOffsetUnicode are
ignored when the ValidDevice flag is clear. parseNetwork read both
regardless, so garbage in those fields became device-name facts or
malformed_structure issues. Read the flags once and only read the device
name fields when ValidDevice is set.

* fix(windows): keep unsupported Tracker headers as raw data

Check TrackerDataBlock Length (0x58) and Version (0) before decoding.
A block with any other header is retained as raw bytes with a
malformed_structure issue, so it no longer yields MAC and timestamp
facts under complete coverage.

* fix(windows): compare shortcut icon paths by normalized location

Collapse "." and ".." segments and repeated separators in the icon
comparison as text only, never opening a path. ".." stops at the drive
or UNC share root, and \\?\ and \\.\ paths stay verbatim.

Join LocalBasePath with CommonPathSuffix as the target and use the bare
base only when the suffix is empty, as the network share branch does.

Read the selected shortcut with lstat and open only, so a rejected
symlink's destination is never resolved.

* fix(windows): keep the UNC share in the root after repeated separators

normalizePath took the host and the next split part as the UNC root, so
\\server\\share\..\app.exe kept an empty share and let .. remove the
real share. Drop empty parts before picking the root so paths on
different shares stay different.

* fix(cli): parse windows shortcut limits as decimals

The four inspect-windows-shortcut limit options now go through
cliDecimalField like the other inspection commands, so values such as
0x10 are rejected and cliDecimalArguments.test.ts passes.

* fix(native): reject linked parents of windows shortcuts

A parent directory symlink or junction pointing at a UNC share was
followed by the first lstat, since the network check reads only the
path text and the symlink rejection covers only the final component.
On Windows, lstat each ancestor from the drive root down and reject
the path at the first link, before anything follows it.

* docs(native): move Windows shortcut guide and add its feature spec

Move the Shell Link guide to docs/guides/native/windows-shortcut.md and
list it under Native binaries in the site navigation, keeping the
/windows-shortcut public route. Update README, translated README, CLI
page and authored skill links to the new physical path.

Add docs/specs/native/windows-shortcut/ with spec.md, plan.md and
tasks.md, as required by docs/development/documentation.md.

* fix(native): admit the windows shortcut parent walk

On Windows the ancestor link walk ran before the provider's resource
admission, so close() could finish while the walk kept calling lstat.
Run the walk inside the same admission as the read, and check the
caller's signal before each ancestor lstat.

* fix(native): walk the effective parents of windows shortcuts

The ancestor link walk checked every prefix of the path as written, so
C:\alias\..\real\a.lnk was refused when C:\alias is a directory link,
although Windows removes alias\.. before opening the file. Walk the
ancestors left after removing . and .. components, keeping the
caller's spelling, never climbing above an absolute root, and leaving
\\?\ paths as written since Windows does not normalize them.

* test(native): assert the linked parent as a structured fact

The parent link regression matched the phrase "junction, which" in the
refusal message, so a wording edit would fail it. Report the linked
ancestor as observed.linked_ancestor on the input issue and assert that
fact instead of the explanatory text.

* test(native): bound the shortcut close gate and release it in finally

Race the parent walk lstat acknowledgement against inspection settling
with awaitAcknowledgement, then release the gate and join the inspect
and close work in finally so a failure reports its cause instead of
waiting for the Vitest timeout.

* fix(native): walk Windows shortcut parents lazily

windowsAncestors built and kept every parent prefix before the first
lstat, so a path with thousands of components allocated memory
quadratic in its length. It now keeps only the normalized components
and yields each parent from a running prefix as the walk reaches it.

---------

Co-authored-by: Matt Van Horn <[email protected]>
2026-11-09 20:19:44 +08:00
吴佳浩Albenandmorluto 25885b05c0 feat(v8): inspect V8 code cache containers and retained byte patterns (#8993)
* feat(v8): inspect V8 code cache containers and their retained byte patterns

Bytenode-compiled `.jsc` files — the V8 code cache container that `vm.Script`,
`vm.compileFunction` and bytenode 2.x write, and that Node single-executable applications
and Electron apps ship — had no format-native reader. `inspect_binary_layout` shows the
surrounding ELF/PE and `inspect_artifact` inventories the file, but neither decodes the V8
structures, so an agent could not tell which V8 line produced the file, could not learn the
container is metadata rather than source, and had nothing to point at a version-pinned
decompiler. Issue #8543.

`inspect_v8_code_cache` joins the format-native family with `inspect_python_pyc`,
`inspect_erlang_beam` and `inspect_kernel_module`: one explicit local file, bounded parsing,
no execution, no installation, no child process.

**The container is version-dependent, so the reader reports roles with confidence instead
of assuming an ABI.** All eight header words are reported with byte offset, observed value,
the role this reader believes the word has, and whether that role is `confirmed`,
`inferred`, or `unconfirmed`. Only three facts gate admission: the header size this reader
pins, the V8 code cache magic high half `0xc0de` (the low half is
`ExternalReferenceTable::kSize` and varies per build, so it is a build fingerprint rather
than a constant), and a declared payload length that reaches exactly the end of the file.

I derived the field semantics from the producer rather than assuming them, and two findings
changed the design:

- **The word V8 calls the source hash holds the source length on the measured producers.**
  A 54-code-unit source stored `54`, and sources with the same code-unit length but
  different content stored the same value, including a source whose UTF-8 length was 154.
  The reader reports it as `source_length` and the docs say that this name is what the
  measurement supports, not a claim about what another build stores there.
- **`vm.compileFunction` sets a high bit in that word.** The reader masks it out and reports
  the producer family as `script` or `compile_function`, so the source length stays correct
  for both producers.

Embedded strings are reported as **byte-pattern observations with absolute byte ranges**,
labelled as such in the field name and in the limitations. A reported sequence is not proof
V8 retained it as a string, and a missing literal is not proof it is absent.

**Fail-closed boundaries, all covered by tests:** an unknown magic is a typed
`unsupported_target` failure because the file is not a V8 code cache; a short header or a
payload-length disagreement is a typed `invalid_request` failure. Neither yields a partial
parse and neither records Evidence.

Non-goals are explicit in the tool description and the docs: the payload is serialized V8
heap data, not source; recovering logic needs a version-pinned View8-style decompiler that
this tool neither provides nor depends on.

Fixtures are generated from the running V8 instead of committing a version-pinned binary, so
the tests exercise the real producer and stay valid across Node upgrades.

- Semantic owner and earliest changed stage: format-native V8 code cache container decoding.
- CLI and MCP/tool-catalog contract: one new `artifact-provider` tool and one new
  `inspect-v8-code-cache` CLI command, registered in `TOOL_CONTRACTS`, the `artifact`
  language family, `TOOL_EFFECTS`, the capability declarations and services, and the
  capability inventory. `docs:check` passes, so the generated catalog agrees.
- Provider, bridge, target-format, or platform compatibility: no provider runs and no
  external tool is required, so the tool is available on every supported Node host.
- Evidence, artifact, provenance, or reconstruction contract: complete Evidence with the
  payload byte range as its location; no artifact format, reader, or reconstruction change.
- Generated metadata, package, or installation impact: catalog and document facts
  regenerated by the existing checks; no new dependency.

Expected effects:

- [x] Target content is returned as bounded structured facts.

- `src/v8/V8CodeCacheParser.test.ts` (13 cases): real-producer header facts, per-field role
  and confidence, source length for both producers, an observation's absolute offset
  verified against the file bytes, the limitation text, foreign magic, payload-length
  mismatch, short header, missing payload bytes, a different build constant still admitted,
  and the observation budget.
- `tests/boundary/mcp/v8CodeCacheMcp.test.ts` (4 cases): advertisement and annotations,
  header facts over MCP, relative-path rejection, unsupported magic, malformed container.
- `tests/acceptance/v8CodeCacheCli.test.ts` (4 cases): the public CLI, relative-path
  resolution, byte-range observations, and the typed failure.

- `npx vitest run src/contracts src/v8 src/application/v8CodeCache src/domain/v8` — 242 passed
- `npx vitest run tests/boundary/mcp/v8CodeCacheMcp.test.ts tests/acceptance/v8CodeCacheCli.test.ts tests/boundary/filesystem/productCatalog.test.ts tests/acceptance/tools/localToolContracts.test.ts` — 20 passed, 4 skipped
- `npx tsc --noEmit -p .` — exit 0
- `npm run build` — exit 0
- `npm run lint` — 0 errors
- `npm run knip` — exit 0
- `npm run docs:check` — exit 0
- `npx oxfmt --check src tests docs` — exit 0

Gap: the header table is measured on node v24.22.1 / V8 13.6.233.17-node.58 only. No other
V8 build is available here, so a different build's field order is untested; that is exactly
why only three facts gate admission and the remaining roles carry a confidence level rather
than being asserted.

Additive. No existing tool, schema, or behaviour changes. The reader never executes the
selected file, never launches a process, and never accesses the network; its audited effects
are `mutatesSession: true` only, matching the other static format readers.

Human owner: @XiaoBinGan

- [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
- [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
- [x] I declare this PR ready for initial maintainer review.

- [x] This PR addresses a concrete problem or an agreed enhancement.
- [x] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
- [x] The PR has one focused outcome and the title follows `type(scope): outcome`.
- [x] Related issue: #8543.
- [x] Tests cover changed observable behavior and meaningful failure paths.
- [x] Owning docs, contracts, and generated metadata are updated where needed.
- [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

* chore: retrigger title and readiness checks after the title was corrected

* fix(v8): bound the payload scan and use the repository path conventions

Review feedback from @greptile-apps on four points.

**Bound the synchronous payload scan.** The scan is one synchronous pass over the
payload, so the 512 MiB ceiling allowed a single request to hold the process for
several seconds. The ceiling is now 64 MiB, matching the pinned CPython pyc reader,
and the default is 32 MiB. The scan stays synchronous, like the BEAM and ELF note
readers in this family, but the budget that bounds it is no longer large enough to
matter. The new `max_file_bytes` ceiling and default are documented.

**Use the absolute-path schema.** `path` now uses `absoluteLocalPathStringSchema`
instead of `localPathStringSchema`, matching `inspect_erlang_beam`. A relative name
previously passed validation and was resolved against the server's working
directory, so `module.jsc` could select a different file than the caller meant. The
rejection is now at the schema boundary.

**State the extraction step.** The handoff in `docs/v8-code-cache.md` now says a
cache embedded in a single-executable application or an Electron app must be
extracted first, because this reader requires the magic at byte zero and returns
`unsupported_target` for the surrounding ELF/PE executable.

**Load only the owning contract group in tests.** Both tests now import
`V8_CODE_CACHE_TOOL_CONTRACTS` directly instead of resolving the tool through the
full catalog, so a focused test no longer constructs every other tool's schema.

21 cases pass across the parser, MCP boundary and CLI acceptance files; `tsc` 0;
`build` 0; `knip` 0; `docs:check` 0; `oxfmt --check` 0.

* fix(v8): select the tool contract by name in the focused tests

Reverts the catalog-position selection I added for a review suggestion. This
repository has a lint rule (`rea(no-positional-tool-contract)`) that forbids
selecting a tool contract by catalog order, and `toolContract("inspect_v8_code_cache")`
is how every neighbouring focused test selects one. The positional form I tried
introduced two lint errors, so the named form stays.

The review concern was that resolving through the full catalog constructs every
other tool's schema. That cost is real but it is the repository's chosen trade:
catalog ordering must never select an operation or schema, and `toolContract` is
the named accessor that enforces it.

* test(v8): cover the new tool in the absolute-path boundary test

Main added `tests/boundary/mcp/absoluteLocalPathTools.test.ts` after this branch
was opened. It enumerates every tool whose MCP `tools/list` schema must reject a
relative path, and `inspect_v8_code_cache` uses `absoluteLocalPathStringSchema`,
so the tool belongs in that list. Adding it keeps the enumerated field set complete
instead of leaving one absolute-path tool untested.

`tests/boundary/mcp` + v8 + contracts: 256 passing. `tsc` 0; `build` 0; `knip` 0;
`docs:check` 0; `npm run lint` 0 errors.

* perf(v8): read the payload by index instead of allocating per byte

`for (const [index, byte] of payload.entries())` allocates a two-element array for
every byte of the cache payload. On a 1 MiB payload that allocation dominated the
scan.

Measured with a real cache built from this parser, alternated so the two forms run
against the same input:

| payload | entries() | indexed reads |
| --- | --- | --- |
| 1 MiB | 15.5ms | 4.4ms |

That is 3.49x on the scan, and the gap widens on smaller payloads where the
allocation cost is a larger share (7.3x at 64 KiB in a synthetic run of the same
shape). The scan is the whole cost of `inspect_v8_code_cache` once the file is read,
so this is the tool's own hot loop.

Output is unchanged: the parser returns one retained string for the 64 KiB fixture,
and `src/v8` plus the CLI and MCP boundary files stay at 21 passing. `tsc` 0;
`build` 0; `npm run lint` 0 errors.

* fix(v8): admit only decimal tokens on the numeric CLI options

Main added `tests/boundary/cli/cliDecimalArguments.test.ts` after this branch was
opened. It enumerates every numeric CLI option and requires `0x10` and `1e3` to be
rejected, because plain `Number` coercion would read them as 16 and 1000. This
command's three options forwarded the domain fields unchanged, so the test failed on
them:

    inspect-v8-code-cache options.maxFileBytes: Parser.parse accepts 1e3
    inspect-v8-code-cache options.maxStrings: Parser.parse accepts 0x10
    inspect-v8-code-cache options.maxStrings: Parser.parse accepts 1e3
    inspect-v8-code-cache options.minStringBytes: Parser.parse accepts 0x10

`cliDecimalField` publishes the input view that parses the decimal token first and
then lets the domain field own bounds, defaults and help, which is what the other
numeric commands use.

`tests/boundary/cli/cliDecimalArguments.test.ts` now passes. `tsc` 0; `build` 0;
`npm run lint` 0 errors; `knip` 0; `docs:check` 0.

* fix(v8): recognize module caches, and advise from remaining headroom

Two review findings, each measured on Node 24.22.1 before changing anything.

**A module cache was reported as a script.** `vm.SourceTextModule.createCachedData()`
sets bit 30 of the source-length word, which the source-length mask `0x1fffffff` leaves
out, and the producer check only tested the function bit at bit 29:

| producer | source word |
| --- | --- |
| `vm.Script` | `0x00000013` for a 19-unit source |
| `vm.compileFunction` | `0x20000009` for a 9-unit source |
| `vm.SourceTextModule` | `0x40000013` for a 19-unit source |

So a real module cache was labelled `script`, and `vm.Script` rejects that container. The
producer enum gains `module` and the module bit is tested first; the source length is
unchanged because both flags sit outside the mask.

**The budget advice recommended a retry that could not work.** Both limits have
ceilings — `max_strings` at 65536 and `min_string_bytes` at 256 — so an admitted file
with more than 65536 runs of 256 bytes reached the branch while every suggested retry
was a rejected input. `observationBudgetRemediation` now reads the remaining headroom
and only recommends a change that is still admissible, falling back to selecting a
smaller artifact when neither can move. The parser message states the fact and leaves
recovery to the provider, which is the only place that can see both budgets.

`MAX_INSPECT_V8_CODE_CACHE_MIN_STRING_BYTES` names the `min_string_bytes` ceiling that
the schema previously spelled inline, so the advice and the schema cannot drift.

`docs/v8-code-cache.md` describes both flag bits. `src/v8` plus the CLI and MCP boundary
files: 28 passing; 7 new cases fail on the base commit. `tsc` 0; `build` 0;
`npm run lint` 0 errors; `knip` 0; `docs:check` 0.

* refactor(v8): decide the budget recovery as data, and test the decision

The remediation tests matched fragments of the advice sentence and banned old phrases.
`docs/testing.md` asks for error codes, recorded limits and recovery behaviour instead of
frozen prose, so a harmless reword could fail those tests while wrong advice passed them.

`observationBudgetRecovery` now returns the decision — which retries remain within the
schema's admitted range, and whether a smaller artifact is the only option — and
`observationBudgetRemediation` renders one sentence from it. The tests assert the
decision, so the wording is free to change and an incorrect choice cannot pass.

This also fixes a bug in the previous shape: it took the `min_string_bytes` branch to mean
"lower it", but that branch is reachable with the value already at the schema minimum,
where lowering is not a legal retry. The decision now carries `canLowerMinStringBytes`
and a `requiresSmallerArtifact` flag for that case.

5 cases, all failing on the base commit, covering both headroom states, either ceiling
alone, and the run-length floor. `src/v8` plus the CLI and MCP boundary files: 28
passing. `tsc` 0; `build` 0; `npm run lint` 0 errors; `knip` 0; `docs:check` 0.

* ci: rerun after the wakaru release download recovered

The only failing job on this branch was `javascript_recovery / real-javascript-recovery`,
which failed on `curl: (22) The requested URL returned error: 504` while downloading
`wakaru-linux-x64.tar.gz`. The release is reachable again (HTTP 200), so this empty
commit re-triggers the lane.

* docs(v8): place the guide in the tree and record the feature

The guide sat at `docs/v8-code-cache.md`, outside the `docs/guides/` tree every other
guide uses, and neither index linked it, so it could not be reached from
`docs/README.md` or the VitePress sidebar.

Moved to `docs/guides/javascript/`, linked from both indexes, and recorded the feature
under `docs/specs/v8-code-cache-inspection/` with `spec.md`, `plan.md` and `tasks.md`.
The spec keeps only the premises that were measured on Node 24.22.1 — the three producer
words and the retained-string layout — rather than restating the implementation.

`npm run docs:check` 0; `npm run format:check` 0; `tsc` 0; `build` 0; `lint` 0 errors;
`knip` 0. V8 reader, CLI and MCP files: 28 passing.

* docs(v8): use the documented spec path and test the advice against its struct

Two review findings.

**The records were at `docs/specs/v8-code-cache-inspection/`.** `AGENTS.md:73` asks for
`docs/specs/<domain>/<feature-slug>/`, so they move to
`docs/specs/v8/code-cache-inspection/`.

**The verification section claimed more than the tests do.** It said the producer cases
were built from real `vm.Script`, `vm.compileFunction` and `vm.SourceTextModule` output,
and that the budget advice was compared with its owning formatter. In fact only
`vm.Script` and `vm.compileFunction` are real producers — the module case sets the
measured bit on a `vm.Script` cache — and only `observationBudgetRecovery` was asserted.

Corrected the claim, and closed the second gap rather than only describing it:
`observationBudgetRemediation` now has four cases holding the sentence to the struct it
renders from. The sentence must not advise a knob the struct closed, and must mention a
smaller artifact exactly when the struct requires one. Verified by making the sentence
advise `max_strings` after the ceiling was reached — the test fails. Wording stays free;
wrong advice does not.

`npm run docs:check` 0; `npm run format:check` 0; `tsc` 0; `build` 0; `lint` 0 errors;
`knip` 0. V8 reader, CLI, MCP, absolute-path and decimal-argument files: 34 passing.

* fix(v8): restore the absolute-path contract entry after the rebase

The rebase onto `main` conflicted in `tests/boundary/mcp/absoluteLocalPathTools.test.ts`:
`main` gained `inspect_api_contract`, `inspect_devicetree`, `inspect_playwright_trace` and
`inspect_python_pyc` in both the contract list and the path-field map while this branch
added `inspect_v8_code_cache`. Both sides are additive, so both are kept.

Without the resolution the branch carried conflict markers, which made `mergeable_state`
`dirty` and every check on it meaningless. Re-verified after the rebase: `tsc` 0, `build` 0,
`format:check` 0, `lint` 0 errors, `knip` 0, `docs:check` 0, and the V8 reader plus its CLI,
MCP, absolute-path and decimal-argument boundary files at 34 passing.

* test(v8): pin the producer from the runtime's own header word

An independent reviewer ran these files on Node 22.23.4, 24.22.1 and 26.12.1. Only 22.23.4
failed, on `separates the compileFunction producer bit from the source length`, expecting
`compile_function` and reading `script`.

The cause is the fixture, not the parser: `vm.compileFunction(...).cachedData` carries
`0x20000009` in the source-length word on Node 24.22.1, with bit 29 set, while Node 22.23.4
does not set that bit at all. Whether a given V8 build marks the word is a build detail, so
asserting one build's spelling made the check version-dependent.

The case now reads the word the runtime produced and asserts the parser maps it correctly,
and keeps the part that must hold everywhere: the source length is the low bits, so it
equals both `word & 0x1fffffff` and the source's length. The flag meanings themselves stay
pinned by the synthetic `withHeaderWord` cases above, which do not depend on any build.

Reverting the parser's `compile_function` arm fails this case and
`keeps the function and module flags distinct`. `src/v8` plus the CLI, MCP and absolute-path
boundary files: 24 and 34 passing. `tsc` 0; `build` 0; `npm run format:check` 0;
`npm run lint` 0 errors; `knip` 0.

* fix(v8): report an unflagged producer word as unknown, not as a script

`vm.compileFunction` marks bit 29 of the source-length word on Node 24.22.1 (`0x20000004`
for a 4-unit source) and does not mark it on Node 22.23.4 (`0x00000004` for the same call).
Whether a V8 build marks a function cache is therefore a build detail, and an unflagged
word is either a `vm.Script` cache or an unmarked function cache. The container carries
nothing that separates the two.

The reader reported `script` for that case, which is a confident claim the bytes do not
support. My previous commit made the test accept whichever value the runtime produced,
which recorded the ambiguity instead of resolving it in the contract. `unknown` is now a
producer value, the unflagged word maps to it, and the observed word stays in
`header.fields` for a caller that trusts a specific build fingerprint. A limitation line
says the same in the report itself.

`header.producer` widens to `["script", "compile_function", "module", "unknown"]`; `script`
is no longer produced, because no unflagged word can be shown to be one.

The spec's producer rule and its verification notes are updated to match. Reverting the
mapping to `script` fails 2 of the 24 `src/v8` cases. `src/v8` with the CLI, MCP and
absolute-path boundary files: 33 passing. `tsc` 0; `build` 0; `docs:check` 0;
`npm run format:check` 0; `npm run lint` 0 errors. `knip` reports one unused export
(`builtinDataEffectMethod`) on `main` as well, so it is not from this change.

* fix(artifacts): retain completed identity across native parser failures

* docs(v8): preserve unknown unflagged cache provenance

---------

Co-authored-by: morluto <[email protected]>
2026-11-09 20:17:25 +08:00
2c27c2a43b feat(electron): report V8 cachedData compilation boundaries (#9501)
* feat(electron): report V8 cachedData execution boundaries

analyze-javascript-application treated new vm.Script(source, {cachedData}) and vm.compileFunction(..., {cachedData}) as ordinary source. V8 deserializes previously compiled bytecode for those calls, so an Electron preload wrapper that delegates its whole contextBridge and IPC surface to a .cache/.jsc snapshot appeared to have been fully analyzed with zero exposed APIs.

Record each vm compilation with its inert cache path when the cachedData value traces to a readFileSync/readFile of path syntax, and project a cached-data execution unknown plus a loads edge from the owning source. Compilations without a cache stay recorded as no-cached-data so absence remains distinguishable from an unparsed snapshot. Count cachedData executions in the Electron summary and state the coverage limit in the graph limitations.

* style(cli): wrap the native data type path description

The `inspect-native-data-type` argument description line is 82 columns, over the repository's 80-column `.oxfmtrc.json` limit, so `npm run format:check` fails on main and on every branch merged from it. It came in with #9465 and the following commits to this file did not touch it. Reformat the one call the formatter objects to; no behaviour change.

* style(domain): reformat the pending dynamic-code accumulator field

`npm run format:check` fails on this branch, which is what `Static checks` reports: oxfmt wants the `pendingDynamicCode` union on one line. Applying it is the whole change; no behaviour is touched.

* fix(electron): preserve VM callable and cache source uncertainty

* docs(javascript): specify cached-data compilation boundaries

* fix(electron): exclude disabled caches from recovered boundaries

---------

Co-authored-by: 2SinceJuly <[email protected]>
Co-authored-by: morluto <[email protected]>
2026-11-09 20:16:18 +08:00
ab1b9e35d0 fix(entropy)!: own selected Windows path spelling at admission (#9393)
* fix(evidence)!: keep one Evidence identity across Windows path case

On Windows, an existing caller path now takes its filesystem spelling when
that spelling differs from the resolved path by letter case alone. One file
spelled `C:\Temp\x.bin`, `c:\temp\x.bin` or `C:\TEMP\X.BIN` produces one
`parameters.path`, `normalized_result` path and `evidence_id`, matching the
existing separator and `.` folding. `caller_input_path` keeps the input.

Links, junctions, `subst` drives, 8.3 short names and paths that do not
exist yet keep the caller spelling, so no link is followed and requested
output names keep their case.

BREAKING CHANGE: Windows Evidence produced from a path spelled in a case
other than its filesystem spelling now gets a different `evidence_id`.

Fixes #9373

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(entropy): keep Windows casing lookup optional

* ci(entropy): select Windows identity verification

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: morluto <[email protected]>
2026-11-09 20:16:13 +08:00
morluto bf271ba3fb fix(capture): retain safe caller path selections (#9626)
* fix(cli)!: retain repeated WASM input paths

BREAKING CHANGE: caller_input_paths values may now be ordered arrays of strings as well as strings. Clients must accept both forms.

* fix(capture): retain safe caller path selections

* fix(evidence): retain auxiliary selections in direct summaries

* test(wasm): separate SDK schema and acquired-input coverage
2026-11-09 20:12:45 +08:00
morluto dda2d40295 fix(desktop): verify process generation for window attribution (#9628) 2026-11-09 19:53:29 +08:00
0b1a945d69 fix(electron): model view constructors as window-like surfaces (#9571)
* fix(electron): model view constructors as window-like surfaces

Electron's static pass recognized a window only through the literal
`BrowserWindow` constructor, so `BaseWindow`, `BrowserView` and
`WebContentsView` produced no node and their literal `webPreferences` were
invisible. IPC registrations reached through such a view's own
`webContents.ipc` were dropped too, because the receiver resolver had the
same single-constructor gate -- VS Code alone registers seven channels this
way, and a shipped sample of four applications put 29 percent of window
construction sites on an unmodeled constructor.

Read webPreferences through one constructor set shared by the construction
inspector and the IPC receiver resolver. The finding only carries the new
`window_constructor` field when the site is not `BrowserWindow`, so existing
projections and their evidence stay byte-identical. A non-BrowserWindow
owner is not admitted for `loadFile`/`loadURL` on itself: only BrowserWindow
exposes those directly.

* fix(electron): keep the view constructor label lookup nullable

Observation labels are nullable in the application graph schema, so the
byLabel lookup failed tsc with TS18047 and took the Static checks job
down with it.

---------

Co-authored-by: 2SinceJuly <[email protected]>
Co-authored-by: morluto <[email protected]>
2026-11-09 19:53:11 +08:00
Taksh Kothariandmorluto 425581e838 fix(cli): validate paths before capture file admission (#9318)
Co-authored-by: morluto <[email protected]>
2026-11-09 19:43:21 +08:00
morluto f047624018 fix(gpu): reject impossible offload bundle counts before capacity (#9621)
fix(gpu): validate bundle count against directory extent
2026-11-09 19:43:13 +08:00
morluto 62a2814756 fix(windows): bound endpoint reads and retain failed file cleanup (#9620)
fix(windows): bound Ghidra endpoint reads
2026-11-09 19:43:07 +08:00
morluto 400a91b5f9 fix(cli)!: retain repeated WASM input paths (#9624)
BREAKING CHANGE: caller_input_paths values may now be ordered arrays of strings as well as strings. Clients must accept both forms.
2026-11-09 19:43:01 +08:00
morluto 8dc2d7bec4 fix(firmware): retain command output after report read failure (#9622)
* fix(javascript): preserve recovery report cancellation

* fix(javascript): retain recovery output on report failures

* fix(firmware): retain output on report read failure
2026-11-09 19:42:54 +08:00
908d9c0726 fix(javascript): keep export bindings out of module views (#9486)
* fix(javascript): keep export bindings out of module views

Exported symbol bindings reuse the javascript-module node kind, so the modules collection counted one row per export alongside the owning module. On a CommonJS or ESM file with N exports, inspect_analysis_view reported N+1 module units, module pages listed indistinguishable rows sharing the module path, and item selection by selector.path failed with "Multiple modules have path".

Treat a node whose observations carry semantic_role export-binding as an export of its owning module, not a module unit, and exclude it from module entries. Export bindings remain distinct graph entities for export-shape comparison and version matching.

Validation: a domain regression in analysisView.test.ts and a CLI acceptance regression over a real CommonJS analysis both fail on main and pass with this change. Also ran the analysis view, MCP boundary, CLI boundary and JavaScript acceptance suites (125 tests), npm run check:fast, and the MCP catalog schema test after regenerating .cache/mcp-tool-catalog.json.

* test(javascript): run the export-binding view case on the shared CLI

The case starts a compiled CLI process for each of its three commands,
paying startup and tool registration three times per run. The fixture
already provides a file-scoped process for calls with no stdin or explicit
timeout, so use it.

* style(javascript): format the constructed-evidence type in the module-view case

The acceptance case's inline graph type did not match what oxfmt emits for the
80-column limit, so `format:check` refused the tree. Reflow only; the assertions
are unchanged.

* style(cli): wrap the native data type path description

The `inspect-native-data-type` argument description line is 82 columns, over the repository's 80-column `.oxfmtrc.json` limit, so `npm run format:check` fails on main and on every branch merged from it. It came in with #9465 and the following commits to this file did not touch it. Reformat the one call the formatter objects to; no behaviour change.

---------

Co-authored-by: 2SinceJuly <[email protected]>
Co-authored-by: morluto <[email protected]>
2026-11-09 19:42:47 +08:00
morlutoandhhang 6a24e801ea fix(elf): qualify Linux CORE notes by the declared ABI (#9613)
* fix(elf): qualify Linux CORE notes by the declared ABI

* test(mcp): cover source fitting and omitted delivery budgets

---------

Co-authored-by: hhang <[email protected]>
2026-11-09 19:42:40 +08:00
morluto 5e61ae0b0e fix(process): preserve failed Darwin helper compilation for waiters (#9610)
fix(process): preserve retiring Darwin compiler failures
2026-11-09 19:42:32 +08:00
7baed55130 fix(doctor): probe providers with the selected client's registration environment (#9108)
* fix(doctor): probe providers with the selected client's registration environment

rea doctor read provider settings only from the terminal running it. A client
registration that carries GHIDRA_INSTALL_DIR or REA_JADX_MCP_CONFIG under its
own env block therefore looked unconfigured: doctor answered not_configured
while the server that client starts inherited the settings and worked. This is
the recovery command the docs point agents at, so the false negative sent them
back to re-apply fixes that were already in place.

When the caller names exactly one client, read that registration's effective
environment and hand it to the provider checks. Terminal variables that
providers resolve outside server config (PATH, SYSTEMROOT) stay inherited, and
running doctor without --client still reports this terminal. A registration the
loader cannot read keeps its own registration check as the answer instead of
being re-reported as four missing providers.

Fixes #9102

* fix(doctor): keep setup's terminal settings and a failed close on the host

Greptile found two regressions in the selected-client environment read.

Provider probes now start from the terminal and overlay the selected
registration, instead of replacing the terminal with the registration
alone. `rea setup --client` passes its own client selection through the
same doctor call, so on a first run with GHIDRA_INSTALL_DIR exported and no
registration yet, the replacements made setup report providerConfigured:
false and offer Hopper over the selected BYO provider. The registration
still wins for every value it records.

The registration read now runs inside the caller's resource scope and, when
the close of the configuration file fails, retains the returned owner there
so host.close() retries it. Dropping that owner left an unretired handle
with no way to report the unfinished cleanup.

* fix(doctor): leave a registration's expression settings unknown

Greptile found the previous fallback filling a name the selected client
records as a Cordis expression with the terminal's value. `dsh` keeps such
a value as `!!js ...`, which is not a literal; the parser reports the name
in `unresolvedSettings`, and merging the terminal into it then made probes
certify a setting the client owns and this process cannot read.

Unresolved names are now removed after the overlay, and an unreadable,
malformed, or unresolvable registration returns no environment at all, so
the caller keeps the terminal instead of a partly-known one. Provider checks
report those settings as unconfigured, which is the honest answer for a
chain that resolves outside REA.

dsh's missing registration still inherits the terminal, which is the case
`rea setup` depends on.

* fix(doctor): fold registration settings by platform identity

`selectedProviderSettings` overlaid a selected client's registration on the
terminal with an object spread. On Windows a registration can record
`ghidra_install_dir` while the terminal exports `GHIDRA_INSTALL_DIR`; the spread
kept both spellings, and since provider checks read the canonical uppercase
names, doctor either certified the terminal's install or reported the setting as
unconfigured. An expression the registration marks unresolved was skipped under
one spelling while its terminal value survived under the other.

Merge the two layers through `mergeEnvironmentOverrides` and fold the result
with `snapshotEnvironment`, so the registration's value wins regardless of how
it spells the name and the provider sees the names it reads. Fold the unresolved
names the same way before deleting them, and export the helper so the two
platform identities can be covered directly.

* style(doctor): wrap the long import in the runtime test

oxfmt wants the three imported names on their own lines; the previous
commit left the single-line form, which fails `npm run format:check`.

* test(codebuddy): construct the registration command like its sibling clients

`npxRegistrationCommand` was removed in c77735fa ("fix(setup)!: bind managed
registrations to selected installation"). The CodeBuddy boundary test landed
after that refactor and still imported it, so `npm run typecheck` failed on
every branch that descends from merge fb841a95 — main included, where the
main push CI is still queued.

Use `currentClientRegistrationCommand()` the way the kimi, lmStudio and other
client configuration tests already do.

Co-Authored-By: Claude Sonnet 5 <[email protected]>

* fix(doctor): retain failed registration file cleanup

* fix(doctor): preserve unknown client provider readiness

* fix(doctor): scope Kuna readiness to its environment

* test(doctor): respect Kuna host support

* fix(doctor): read a registration's unresolved settings only where the probe needs them

Every setting an expression made unresolved blocked readiness, even one the provider never consults for the configuration the client supplied. With a literal JAVA_HOME and jar path, JADX resolves Java by absolute path and does not read PATH, yet a dsh registration with an expression-backed PATH skipped the probe and reported the provider unknown. Ghidra is the same when both GHIDRA_INSTALL_DIR and JAVA_HOME are explicit.

Decide per provider which unresolved setting the probe actually reads, and skip only those. Kuna's readiness list also omitted HOME and XDG_CACHE_HOME, which its cache root falls back to, so an unresolved cache input could let the probe check a fallback directory and report available without knowing the client's real cache.

* fix(doctor): stop probing a registration expression as a literal

Two findings from the review, both about handing a probe a value REA cannot interpret.

REA_KUNA_CACHE_DIR made settingAffectsProbe ignore every unresolved Kuna setting, so an expression-backed REA_KUNA_COMMAND or REA_KUNA_JOBS silently fell back to a default and the provider could report ready. Limit the exception to HOME and XDG_CACHE_HOME, the two cache-location defaults.

HOME and XDG_CACHE_HOME were also added to KUNA_DOCTOR_SETTINGS, which registrationEnvironment copies wholesale, so setup persisted ambient values a child already inherits. Split the readiness inputs from the settings setup writes.

Qwen expands $VAR and ${VAR} in a recorded env value from the environment it runs with. REA cannot predict that, but it was handing the literal to the probes, so a registration appending to PATH made JADX search for a literal ${PATH} entry. Treat such values as unresolved for that client so the affected provider reports unknown instead of probing the literal text.

* fix(registration): recognize a client's env expression at the shared reader

Doctor decided which Qwen settings were expressions after the shared registration reader had already parsed them as literals, so doctor and setup/status held two interpretations of the same file. AGENTS.md requires normalizing once at the owning boundary, so move the recognition into ClientRegistrationEnvironment and let every consumer read the facts it returns.

The reader now takes the client name, marks a variable-expanding client's $VAR and ${VAR} values as unresolved, and reports those names through unresolvedSettings. Doctor drops its own parser; setup and status pick up the same facts, which also keeps an expression-valued timeout out of the resolved budget instead of trusting the literal.

* fix(doctor): preserve unresolved typed settings

* style(cli): wrap the native data type path description

The `inspect-native-data-type` argument description line is 82 columns, over the repository's 80-column `.oxfmtrc.json` limit, so `npm run format:check` fails on main and on every branch merged from it. It came in with #9465 and the following commits to this file did not touch it. Reformat the one call the formatter objects to; no behaviour change.

---------

Co-authored-by: 2SinceJuly <[email protected]>
Co-authored-by: Claude Sonnet 5 <[email protected]>
Co-authored-by: morluto <[email protected]>
2026-11-09 19:42:25 +08:00
512bcf5cdb fix(javascript): analyze first-party sources before dependencies (#9341)
* fix(javascript): analyze first-party sources before dependencies

Every source in one application analysis charges the same parent result
budget, and sources were offered in lexical inventory order. On an Electron
app.asar, node_modules/ sorts before an electron-vite out-*/ directory, so
dependency files spent the budget and every first-party main, preload, and
renderer file had its semantic analysis not started and its application
projection rejected. The summary then reported zero windows, preloads, and
bridges while electron_semantics still said "recovered".

Offer application JavaScript before JavaScript under node_modules; reported
files keep inventory order. Count Electron boundary facts only from files
whose projection was admitted, and report electron_semantics "partial" (with
a limitation naming the count) when an Electron-loading source was not fully
examined or reported.

Fixes #9321

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(javascript): treat limited Electron examination as partial coverage

A static pass can stop early at the Electron wrapper expansion budget or
another resource limit without failing the worker. Such a source carries no
analysis or projection failure, so its retained IPC or bridge facts still
reported electron_semantics "recovered". Read the owned examination status
and count a limited Electron-loading source as incomplete.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: morluto <[email protected]>
2026-11-09 19:42:19 +08:00
morluto 31b6db72c6 fix(environment): avoid attributing overlapping writes (#9614) 2026-11-09 19:42:13 +08:00
morluto 3e1f70096b fix(cli): retain selected IL2CPP binary path (#9623) 2026-11-09 19:42:06 +08:00
morluto e8d1bbc98b fix(reference): preserve import cancellation provenance (#9597)
* fix(reference): preserve import cancellation reason

* test(reference): cover null cancellation during failed cleanup

* test(reference): always release fixture directory
2026-11-09 19:42:00 +08:00
morlutoandhhang e66e92904e fix(desktop): preserve trailing spaces in desktop entry values (#9612)
* fix(desktop): preserve trailing spaces in desktop entry values

* test(mcp): cover source fitting and omitted delivery budgets

---------

Co-authored-by: hhang <[email protected]>
2026-11-09 19:41:54 +08:00
morluto 8c64eb511f fix(ghidra): stage NativeAOT report until recovery completes (#9611)
* fix(ghidra): stage nativeaot recovery report until complete

* test(ghidra): exercise nativeaot rollback reporting
2026-11-09 19:39:51 +08:00
morluto e304de99bc fix(desktop): retain published capture evidence on late cancellation (#9591)
fix(desktop): retain published capture on late cancellation
2026-11-09 19:36:11 +08:00
morluto d307ece767 fix(flutter): validate ELF build ID note padding (#9609) 2026-11-09 19:35:13 +08:00
morluto 4fde832260 fix(rizin): retain failed TTY cleanup ownership (#9608)
fix(rizin): retain TTY admission cleanup ownership
2026-11-09 19:35:07 +08:00
morluto 97fe58d3fe fix(erlang): validate table framing before row capacity (#9606)
fix(erlang): validate BEAM table extents before capacity
2026-11-09 19:35:01 +08:00
morluto 7c821cfea1 fix(hopper): retain bridge after lost shutdown reply (#9604) 2026-11-09 19:34:55 +08:00
morluto f46e9a8479 fix(environment): retain committed bundle receipts after finalization failure (#9602)
* fix(environment): retain published bundle receipts

* fix(environment): retain receipt after tarball lookup failures
2026-11-09 19:34:48 +08:00
morluto 29768c6f53 fix(dotnet): reject negative bundle declarations as malformed (#9601)
* fix(artifacts): reject negative .NET bundle declarations

* test(artifacts): derive .NET fixture field positions
2026-11-09 19:34:35 +08:00
morluto cc13c5d095 fix(native): preserve unknown ARM64 subtype in hardening (#9600) 2026-11-09 19:34:28 +08:00
morluto 897caa814d fix(inspector): drain discovery requests after sibling failure (#9598)
fix(inspector): drain failed discovery requests
2026-11-09 19:34:22 +08:00
morluto a874cef9af fix(adb): report observed output after failed file pull (#9596) 2026-11-09 19:34:16 +08:00
morluto a6c10a28f4 fix(cli): retain JavaScript evidence through final cleanup (#9595)
fix(cli): retain JavaScript evidence after final cleanup
2026-11-09 19:34:10 +08:00
morluto 9536ebb7ca fix(firmware): exclude UF2 payloads overlapping MD5 metadata (#9593)
* fix(artifacts): exclude UF2 payloads overlapping MD5 metadata

* fix(artifacts): clarify DfuSe overlap ordering
2026-11-09 19:34:04 +08:00
914 changed files with 118551 additions and 6382 deletions

No files matched your search

@@ -2,7 +2,7 @@
name: reverse-engineer-anything
description: Reverse engineer native, managed, Electron/JavaScript, packaged, firmware, and browser targets with REA, and build agent environments (AgentEnv bundles) of web applications from a live instance or a capture, and of Linux desktop apps with a task from a request. Use shipped-artifact or requested runtime evidence to explain features, compare versions, decompile code, or guide a reconstruction. Skip REA for ordinary source-repository architecture analysis.
metadata:
version: "61"
version: "62"
---
# REA
@@ -97,6 +97,12 @@ explicit path or endpoint and do not need it.
- Bun `--compile` executable: `open_binary`, then `inspect_artifact`; the Bun
module graph is the application layer. Extract stored modules and analyze the
JavaScript. See [Bun standalone executables](https://github.com/morluto/rea/blob/main/docs/bun-standalone.md).
- Deno `deno compile` executable: `open_binary`, then `inspect_artifact`; the
embedded virtual filesystem is the application layer. Extract stored files and
analyze compatible JavaScript. Environment-file values and CA certificate bytes
are retained in local Evidence with their counts and byte lengths. The npm
snapshot length is reported and not decoded, and the executable is not run. See
[Deno compile executables](https://github.com/morluto/rea/blob/main/docs/deno-standalone.md).
- Apple app plist, Interface Builder, asset catalog, or keyed archive resources:
`open_bundle_resources`, then the selected resource tool. This does not
require `CFBundleExecutable` or a deep provider. Resource sessions have no
@@ -276,6 +282,14 @@ explicit path or endpoint and do not need it.
proof the image never imported APIs through another table. Bound snapshots
and loaded IAT contents remain unobserved. See the
[PE import guide](https://github.com/morluto/rea/blob/main/docs/pe-imports.md).
- Windows Shell Link shortcuts: `inspect_windows_shortcut` with the explicit
local `.lnk` file. This built-in target-free inspection requires no Windows
SDK or COM. Preserve header flags and FILETIMEs, IDList items, LinkInfo
volume and network names, StringData arguments and icon location, ExtraData
signatures, and Tracker droid facts labelled derived. Unknown IDList items
and ExtraData signatures stay raw with SHA-256. The target path is not
resolved or executed. See the
[Windows shortcut guide](https://github.com/morluto/rea/blob/main/docs/guides/native/windows-shortcut.md).
- PE TLS callbacks and load configuration: `inspect_pe_load_config` with the
explicit local PE32/PE32+ file. This built-in target-free inspection requires
no Windows SDK. Preserve callback VAs as strings with their RVA, file offset
@@ -299,6 +313,23 @@ explicit path or endpoint and do not need it.
build-id or ABI-tag fields. A missing table is observed absence of those
declarations, not proof the image never carried notes. See the
[ELF notes guide](https://github.com/morluto/rea/blob/main/docs/elf-notes.md).
- Code that runs before `main` or at exit in ELF or Mach-O:
`inspect_native_initializers` with the explicit local file (and
`architecture` for a universal Mach-O). This built-in inspection requires no
disassembler. Preserve slot and target addresses, the `resolution` of each
entry, and its limitations. An `unresolved` slot is not a zero pointer, and a
missing table is not proof that no constructor exists. See the
[initializer guide](https://github.com/morluto/rea/blob/main/docs/guides/native/native-initializers.md).
- ELF unwind function ranges: `inspect_elf_unwind_ranges` with the explicit
local ELF32/ELF64 file. This built-in target-free inspection requires no
disassembler. Preserve FDE start, end, size, containing section, exact
symbol name, CIE index, LSDA, and personality. Page with `offset` and
`limit`. A missing `.eh_frame` is observed absence of that declaration,
not proof the image has no functions. `.debug_frame` is reported present
or absent and is not decoded. CFA instructions are counted and not
evaluated. See the
[ELF unwind ranges guide](https://github.com/morluto/rea/blob/main/docs/guides/native/elf-unwind-ranges.md).
- Apple `.ips` crash reports: `inspect_apple_ips` with the explicit local
file. This built-in target-free inspection requires no Xcode, atos, or
pwntools. Preserve first-line metadata, `bug_type` as a string, process and
@@ -317,6 +348,16 @@ explicit path or endpoint and do not need it.
zstd containers are unsupported; decompress into a separate file with an
external codec utility, then inspect the decompressed `ET_REL` image. See the
[kernel module guide](https://github.com/morluto/rea/blob/main/docs/kernel-modules.md).
- Linux kernel version and build config (`CONFIG_*` options such as
`CONFIG_SECURITY_SELINUX`): `inspect_kernel_build_config` with the explicit
local `vmlinux`, raw `Image`, x86 `bzImage`, or `configs.ko`. This built-in
target-free inspection requires no Linux host or `extract-ikconfig`. Preserve
the banner version, config SHA-256, option count, and value kinds; use `name`
for one option. An `IKCFG_ST` string is a config only with a valid gzip member
and `IKCFG_ED`. An absent config may mean the kernel was built without
`CONFIG_IKCONFIG`. Non-gzip payloads are unsupported; decompress externally,
then inspect the result. See the
[kernel build config guide](https://github.com/morluto/rea/blob/main/docs/guides/native/kernel-build-config.md).
- CPython 3.7–3.13 `.pyc` header, nested marshal code objects and bytecode
identity: `inspect_python_pyc` with the explicit local file. This built-in
target-free inspection requires no Python installation. Preserve magic,
@@ -5,14 +5,18 @@ task, such as "Build me an Inkscape environment where the agent changes a
poster's headline and saves it". You are the building agent: you drive the
app on a build computer through REA's MCP tools, write the task, export the
bundle and witness it in a fresh computer. REA runs no model. The tools are
MCP-only and need Docker, `REA_AGENT_ENV_COMMAND` and
`REA_BUILD_COMPUTER_REA_ARCHIVE` where the REA server starts; when a start
reports one missing, tell the person what to set and stop.
MCP-only and need a Linux host with Docker, agentenv and REA's packed
runtime. When a start reports one missing, tell the person to run
`rea doctor --provider desktop_build` and apply its fixes, or
`rea setup --client <client> --desktop-build` and restart the client, and
stop.
For the whole build:
- Drive the app only with `act_on_build_computer`. Never script it, run
commands in the computer or write its files another way.
commands in the computer or write its files another way. The one command
you write for the computer is a task's reader, which REA runs to check a
file; it never makes the seed or the edit.
- Ask the upfront questions once, then work on your own. Pause only when
blocked.
- The seed's content is synthetic. Never put real personal data in it.
@@ -22,7 +26,8 @@ For the whole build:
## Ask once, upfront
In one message, ask only what the request leaves open, and keep the list for
the report:
the report. Skip each question the request answers; when it answers them all,
start without asking:
1. The app and the task, if either is unclear: what changes, in which
document.
@@ -31,39 +36,83 @@ the report:
and with which model.
4. If so, whether they want to review the task before those runs.
When you cannot ask, as in a headless `claude -p` run, do not stop: take
these defaults for whatever the request leaves open, say which you took in
your first message and in the report, and go on. Install from the Ubuntu
archive, make a synthetic seed, skip the review, and make 3 solver runs
within $4 in all, with the model the request names or else the runner's
default.
## When you are blocked
Stop, say what you need and wait only for:
- a licence the app or its installer asks someone to accept: never accept it
yourself; name it and where to read it, and go on only once the person
says they accept it;
- credentials: they may only be typed as handles you never see, and the
build tools have none yet, so say the app needs a sign-in and stop. Never
ask for a password in chat;
- a signed-in state in the seed: ask before seeding one;
on your own; name it and where to read it, and go on only once the person
says they accept it. Then record their words with `record_build_consent`,
kind `licence`, and accept it on their behalf;
- credentials: ask the person to write each secret, and nothing else, in a
file named after a handle you choose, such as `keepassxc-master`, in
`~/.config/rea/build-secrets/` on this host (under `$XDG_CONFIG_HOME` when
it is set), readable only by them (`chmod 600`), and wait until they say it
is there; then type it with `type_secret` (see Drive the app). Never ask
for a password or key in chat, and never read, list or print that folder;
- a signed-in state in the seed: by default the export withholds it (see
Sign-in and licence state). Seed it only when the person says the bundle
may hold it: record their words with `record_build_consent`, kind
`seed_sign_in`, and export with `seed_sign_in: true`;
- an install this flow cannot do, below.
Decide everything else yourself and note it in the report.
## Sign-in and licence state
What an app writes when someone signs in or activates a licence is withheld
from the seed: the bundle's receiver supplies their own. Mark
`pre-sign-in` with `mark_build_checkpoint` just before the sign-in or
activation and `post-sign-in` just after, both before `seed`: every file
under the owned paths that changed between them is withheld, and the draft
leaves it out. A file the app writes at first launch, such as a trial's
licence file, changes before you can mark anything: name it in
`export_build_environment`'s `withhold`. The export lists each withheld file
in `withheld_files` with the environment variable a deploy reads it from and
the handle of the secret REA keeps its bytes in; a check may not name one.
The export refuses a seed file holding a withheld file's exact bytes, such as
a `.bak` copy, but a backup that differs from it is not caught: trash backups
before `seed`.
Explicitly withhold any other files the person identifies as sensitive;
REA does not infer secrecy from a value's shape or a file name.
## Choose the install
The computer is Ubuntu 24.04 (noble) on this host's architecture only. Use
the first source that has the app:
| Source | `install` |
| ---------------------------- | --------------------------------------------------------------------------------- |
| Ubuntu archive | `{"kind": "archive", "package": "inkscape"}` |
| PPA or vendor apt repository | `{"kind": "apt_repository", "package", "uri", "suite", "components", "key_file"}` |
| `.deb` by URL | `{"kind": "package_file", "url", "sha256", "architecture", "dependencies"}` |
| Source | `install` |
| ---------------------------- | ------------------------------------------------------------------------------------------- |
| Ubuntu archive | `{"kind": "archive", "package": "inkscape"}` |
| PPA or vendor apt repository | `{"kind": "apt_repository", "package", "uri", "suite", "components", "key_file"}` |
| `.deb` by URL | `{"kind": "package_file", "url", "sha256", "architecture", "dependencies"}` |
| AppImage by URL | `{"kind": "appimage", "url", "sha256", "architecture", "extra_packages"}` |
| Tarball by URL | `{"kind": "tarball", "url", "sha256", "architecture", "program", "name", "extra_packages"}` |
- A PPA's `uri` is `https://ppa.launchpadcontent.net/OWNER/NAME/ubuntu`,
`suite` `noble`, `components` `["main"]`. `key_file` is the repository's
signing key saved on this host; for a PPA, fetch it from
keyserver.ubuntu.com by the fingerprint its Launchpad page shows.
- For a `.deb`, ask the requester for its URL and SHA-256; do not fetch a
vendor's download page yourself. List its `Depends` as `dependencies`:
it installs with the network off.
- When the app exits at launch for want of a runtime piece its package does
not install, start a new build computer with that package in
`extra_packages`, up to 16 archive names; the export installs them too.
MyPaint needs
`{"kind": "archive", "package": "mypaint", "extra_packages": ["librsvg2-common"]}`
for its SVG icons, and Freeplane `["openjdk-17-jre"]`, since its launcher
refuses noble's Java 21. Name one up front, too, when a package the app
only recommends holds its content, such as QElectroTech's element library
`qelectrotech-data`, without which no component can be placed.
- Take the `.deb` path only when the app is not in the archive at all, not
to add a package. Ask the requester for its URL and SHA-256; do not fetch
a vendor's download page yourself. List its `Depends` as `dependencies`,
with any runtime piece it lacks: it installs with the network off.
- Flatpak, AppImage and snaps are not supported yet: say so and stop. An
archive package that only installs a snap, such as noble's `firefox`,
counts as a snap. A package with no build for this host's architecture
@@ -72,6 +121,13 @@ the first source that has the app:
`/usr/share/applications` without `.desktop`, such as
`org.inkscape.Inkscape`. Add `window_class` when you know it; Inkscape's
is `Inkscape`. AbiWord's entry is `abiword` and its class `Abiword`.
- To find the entry, read the package's file list: its page on
packages.ubuntu.com, or `apt-get download PKG && dpkg -c PKG_*.deb` where
apt runs. The entry may ship in a companion `-data` or `-common` package,
as Planner's in `planner-data`: read that package's list too. The entry's `StartupWMClass` may not be the window's real
class, so do not take `window_class` from it: MuseScore 3's says
`mscore3`, its window's is `MuseScore3`. The export uses the class the
capture saw.
## Drive the app
@@ -81,8 +137,10 @@ the first source that has the app:
[the build-computer guide](https://github.com/morluto/rea/blob/main/docs/desktop-build-computer.md).
- Take a `screenshot` before pointing: points are pixels of the latest
frame. If a response is too large, ask for a `region`, or `jpeg` with a
lower `quality`. A region crops the latest frame and becomes it: take a
full screenshot before pointing again.
lower `quality`. A screenshot with `region` does not capture the screen
again; it crops the latest frame, so take a full screenshot, or a `wait`
with `screenshot: true`, first. The crop then becomes the latest frame:
take a full screenshot before pointing again.
- A drawn caret does not prove keyboard focus. After using a toolbar
control, click into the document, then type a few characters and look
before a long text.
@@ -95,25 +153,149 @@ the first source that has the app:
close it while capturing; the capture ends when the app exits. When the
app is closed at any other time, open it from Applications → Other → the
environment's name.
- Type a secret with `{"action": "type_secret", "secret": "<handle>"}`,
only into a field that masks what is typed: check in a screenshot that it
is a password field, which shows dots. A screenshot shows any field that
shows its text, such as many licence-key boxes, so never type a secret into
one: say the app needs a secret the build cannot type unseen, and stop.
`type_secret` takes no `screenshot`; look with a `wait` after it. A refusal
names the secret's file and what is wrong with it: tell the person, never
the value.
- Prefer shortcuts and typing to long pointer paths: `key` takes `keys`, an
array holding one chord's keys, such as
`{"action": "key", "keys": ["ctrl", "s"]}`, and `type` turns `\n` into
`{"action": "key", "keys": ["Control", "s"]}`, and `type` turns `\n` into
Enter.
- Before `type`, check in a screenshot that a text cursor or a focused
field is there. In apps with single-key shortcuts, such as Inkscape, text
typed without one runs as commands.
- Save As opens in the home: click Documents in its sidebar and type only
the file name. Answer the app's save questions, such as keeping the
format, then check the saved path in the title or status bar, or the
dialog's folder when the app shows only the name, and that it shows no
unsaved mark, before you mark a checkpoint or check.
- Save As differs by app. Check the dialog's current folder first: most
open in the home, so click Documents in the sidebar, but Scribus opens in
`~/Documents` and its sidebar has no Documents entry. Type only the file
name. A dialog taller than the 1280×800 screen hides its buttons:
maximize it from its title bar, or confirm it with `key` Return, as when
HomeBank's Save button is off-screen. When a GTK Save dialog ignores
clicks or runs off the screen, type `~/Documents/<name>` in its Name field
and press Return.
- Answer the app's save questions, such as keeping the format, then check
the saved path in the title or status bar, or the dialog's folder when
the app shows only the name, and that it shows no unsaved mark, before
you mark a checkpoint or check. Where the title never shows one, as in
HomeBank, a greyed Save or Revert, or the file reopened from recent
files, confirms the save.
- Qt spin boxes change their value on scroll: move the pointer off them
before you scroll.
- gLabels edits an object's text in Object properties → Text, not on the
canvas.
- In Grisbi's transaction form Return moves to the next field; only Return
in the last field, Notes, records the transaction.
- ghostwriter autosaves a new document as `~/Documents/untitled-1.md`: name
it with File → Rename, not Save As; Ctrl+Shift+S does nothing, and Enter
after a checklist item starts another `- [ ]` item.
- KMyMoney's first launch opens the New File Setup wizard; Finish asks for a
storage type (XML), then a Save As where typing `Documents/<name>.kmy`
works. Its date field is a sectioned Qt editor: double-click the month and
type each part, since Ctrl+A garbles it. A new transaction's payee comes
prefilled and selected. Amounts are saved as reduced fractions, such as
`-1749/20`, so compare them exactly. Untick Help → Tip of the Day → "Show
tips on startup" before `seed`, or the tip appears at every boot.
- QElectroTech: an element dropped from Collections follows the pointer until
a click on the folio places it. Its title shows only the app, so it needs
`state_paths`; its settings are in `~/.qet`.
- Rosegarden: after a dialog its Transport window can take keyboard focus,
so save with File → Save.
- Pencil2D: the Tools dock is too narrow for its buttons, so use shortcuts
(B for the brush); double-click a layer's name to rename it.
- Umbrello: the title shows no unsaved mark, so confirm a save with a probe
checkpoint. An Untitled document autosaves `~/autosave.xmi`: delete it
before `seed`. Add attributes from the tree: right-click the class → New →
Attribute.
- Hydrogen: the computer has no audio device, so Hydrogen falls back to a
null driver and its BPM field snaps back to 120 within about 100 ms.
Before `seed`, set Preferences → Audio System → ALSA with device `null`
and click "Apply and restart output", which `~/.hydrogen/hydrogen.conf`
keeps for the seed; also set autosaves per hour to 0, and dismiss the
development-version dialog with "Don't show again". `pulseaudio` as an
extra package does not help.
- Poedit cannot add entries by hand. Use File → New, pick the language and
save to `Documents` first (Sources Paths stays locked until then), then
Properties → Sources Paths → + → Add Files with a source such as
`/usr/lib/python3.12/argparse.py`. It writes `fr.mo` beside the `.po`, and
the language box's autocomplete popup takes the first OK click.
- CherryTree: its first-run autosave "Choose Storage Type" dialog swallows
keys, so save once early as `.ctd` and untick autosave.
- VSCodium (its tarball, with `extra_packages: ["libnss3",
"libasound2t64"]`) runs on outside REA's reach, so `stop_build_capture`
fails to clean it up: after `end`, quit it with Ctrl+Q, then stop. Enter
accepts its word suggestions, so press Escape after typing a line.
- Glade: a new widget's id is empty until you set it, and a second save
writes a `.glade~` backup, which shows in the draft as an unrelated
change. A backup present at `seed` is seeded with the document, so trash
it before `seed`. The draft names a button's `<child>` by the id
its widget carries, `[name=child][>object@id=submit_button]`, which moving
the button keeps; give the widget an id before `seed` so it can.
- VYM: the title never names the map, so pass `Documents/<map>.vym` in
`state_paths`. Its settings live in `.config/InSilmaril` and are written
only at a clean exit. It writes `<map>.vym.lock` while a map is open, so
close the map before `seed`. Press A only after clicking a branch on the
canvas: keys typed in the tree editor run other shortcuts.
- KmPlot: Create → Cartesian Plot, then edit the formula in the Function
tab and press Return. It stores minus as U+2212 (`−`). Its file:// title
still names the file.
- RedNotebook keeps each month in `~/.rednotebook/data/YYYY-MM.txt`, YAML
read as text, folded at about column 80: pick check phrases the fold keeps
on one line.
- Qt5 apps saving with QDom, such as KmPlot, write attributes in a random
order in each process, so check their XML by element, never by whole line.
- Gnumeric's desktop entry is `org.gnumeric.gnumeric`. Its Save As dialog
runs off the 1280×800 screen: type `~/Documents/<name>` in Name and press
Return. Rename a sheet with right-click on its tab, then Rename….
- Parley's title shows the collection's title, so name the file in
`state_paths`. File → New opens the new collection's Properties dialog:
confirm it with OK, since Cancel keeps the old collection and its autosave
lock open. A new collection starts with 15 blank entries: delete them.
Pick languages from the dropdown; a typed name keeps the previous locale.
While a document is open KDE keeps an autosave and its `.lock` in
`~/.local/share/stalefiles/parley/`, and there is no File → Close: before
`seed`, use File → New, then reopen the collection from Open Recent.
- Sigil: pass `extra_packages: ["libqt5svg5"]`, or its SVG toolbar icons are
blank. Its title names the book, so it needs no `state_paths`. It unpacks
the open book into `.local/share/sigil-ebook/sigil/workspace/Sigil-XXXXXX/`
and deletes it on exit, so never name the whole `sigil-ebook` folder: that
seeds the stale copy.
- What the app saved under the home before `seed`, such as a document in
`~/Documents` or its settings, is part of the seed. A file you move to the
Trash is left out, and the export lists it in `limitations`. Trash a stray
file rather than starting over.
file rather than starting over. JabRef 3.8 writes `<file>.bak` and
`<file>.sav` beside a `.bib` it saves; in the owned folder they are seeded
and show in the draft as noise, so trash them before `seed` if they should
not ship.
- Dismiss first-run dialogs, such as a welcome screen, before `seed`. A
choice the app saves only later, such as Inkscape's "show this every
time", may not reach the seed, so expect the dialog in the witness too.
- Some apps write their settings late: Freeplane writes
`~/.config/freeplane/1.7.x/auto.properties` only once Preferences is
confirmed, and a seed without it reopens its documentation map. Before
`seed`, open the app's preferences and confirm them, then read a probe
checkpoint's `changed_files` to see the settings file written.
- Before `seed`, click into the document to clear any selection the app
would save: Gnote saves its cursor and selection with the note.
- An app whose state folder is named after it, such as
`~/.local/share/gnote`, or after it and its version, such as TreeLine's
`~/.treeline-3.1`, is found without `state_paths`.
- TreeLine: File → New opens a template window. Book List's CATEGORY makes
AUTHOR children by default; change it under Data → Configure Data Types →
Default Child Type. A new child opens an inline rename showing "", so
press Escape and fill its fields in the Data Edit tab. Ctrl+A adds a child
node even while a field has focus. Clicking a node already selected starts
an inline rename, so Ctrl+X then cuts its text: cut a node from its
context menu. It saves nodes sorted by their
generated uid1, so their order changes from run to run. The draft names a
new node by its format and a field of its `data`,
`/nodes/[format=BOOK][>data~1Title=The Silk Roads]`, and checks its other
fields through that, so give each new node a title no other node has.
- After an app crashes, capture again on a fresh computer, so the seed
carries no crash-recovery state, such as MyPaint's "Recover interrupted
work?".
- Give what the task changes a stable name where the app has one, such as an
id in Inkscape's Object Properties, so a check can select it.
- Expect apps to split text into runs: Writer's revision ids split an
@@ -121,17 +303,46 @@ the first source that has the app:
`P1`, and AbiWord wraps each insertion in `<c>`. Check such text whole
with `text_equals` (see Write the task), and find the paragraph by
something the edit keeps, such as AbiWord's `xid`.
- Freeplane's first launch opens a documentation map: close it with Ctrl+W.
Its Ctrl+N asks for a template.
- MyPaint 2.0.1 crashes on brush strokes on the build computer: build its
seed with flood fill and layer operations.
- GnuCash's Ctrl+S on a new book opens a Save dialog with no format choice:
use File > Save As to pick XML. Close the book (File > New File) before
`seed`, so its `.LCK` lock is not seeded.
## Build the seed and the edit
1. `start_build_computer` with
`{"source": {"kind": "request", "desktop_entry": ..., "install": ...}}`.
The first start of an app builds its image and can take minutes. A
failed start returns the build's error: fix the request, or stop when the
The first start of an app builds its image, and starts at the same time
on this host wait for each other; either can take minutes. A failed
start returns the build's error: fix the request, or stop when the
install cannot work, and close any `computer_id` the error names.
2. `start_build_capture`. It returns once the app's window is open. A
`package_lists_error` may stop the capture finding the package's
sources; the export says when that matters.
sources; the export says when that matters. When the app exits before
its window opens, the error gives its exit code and the end of its
stderr, which may name what it lacks, such as an icon loader or a Java
runtime: close the computer and start a new one with that package in
`extra_packages` (see Choose the install), or stop as for an install
this flow cannot do.
- REA counts a file as the app's document only when the app's window
title shows its file name or `~/` path. When the title shows something
else, such as MuseScore's score title, pass the path you will save the
document at in `state_paths`, relative to the home:
`{"computer_id": ..., "state_paths": ["Documents/MuseScore3/Scores/Morning_Song.mscz"]}`.
It need not exist yet. Add the app's settings folder when its name
differs from the app's, such as `.config/MuseScore`, so the seed keeps
the dismissed first-run dialogs. Do not pass the document as a launch
argument to make REA see it: `state_paths` is the way. gLabels' title
leaves out the file's extension and Grisbi's shows the entity's name,
so both need it.
- An app whose document is a folder of pages, such as a Zim notebook
(`Notebooks/Notes`, a `.txt` file per page), never shows a file in its
title: pass the folder in `state_paths`. Every page in it is then a
document, so the bundle opens none at launch and the app starts where
it keeps its place; check the page the task changes.
3. Make the seed through the app and save it from the app under
`~/Documents`: build the document in the app, or write its source where
the app edits its format as text, then save it again from the app. Make
@@ -141,14 +352,71 @@ the first source that has the app:
otherwise starts on its own screen. For a starting file of the requester's,
read it here and rebuild it in the app with synthetic data in place of
personal data; REA cannot copy a file into the computer.
- An app that keeps its own data and saves after every change, such as
Osmo's contacts in `~/.local/share/osmo/contacts_records.xml`, has no
document: that state is the seed. Build it in the app and mark `seed`
once the app has written. To see whether it has, mark a throwaway
checkpoint, such as `probe-1`, and read its `changed_files`: up to ten
files that changed since the checkpoint before, those a window title
named first, then those under `state_paths` and those the app held
open, caches last, with `more_changed_files` counting the rest.
- The app's own compressed format works when it is gzip, such as
Gnumeric's `.gnumeric`, Dia's `.dia` or Inkscape's `.svgz`: REA reads
the document inside, and checks point into it as into the same
document uncompressed. Compression may be off by default: Dia's
"Compress diagram files" is unticked, which REA reads as plain XML. A format REA reads as binary, such as one
compressed with xz, has no view: save in a format the app offers that
REA reads, then reopen the file once and check that a plain Ctrl+S
keeps that format. When the task is about the app's own binary
format, such as GIMP's `.xcf` or Blender's `.blend`, keep it and check
it through a reader (see Read a binary file with a reader).
4. Only once the seed is saved, `mark_build_checkpoint` with name `seed`.
5. Make the change the task asks for, as a user would, and save it.
6. Only once the change is saved, `mark_build_checkpoint` with name `end`.
7. `stop_build_capture`. Read `draft.files` (each file that changed, with
its net change), `draft.task.checks` (suggested checks) and
`limitations`. When `draft` is null, read `draft_refusal` first: a
missing `seed` or `end` checkpoint means capturing again on a new build
computer, while a failed draft command names its own cause to fix.
its net change and its `values`), `draft.task.checks` (suggested
checks), `draft.guards`, `draft.notes` and `limitations`. When `draft`
is null, read `draft_refusal` first: a missing `seed` or `end`
checkpoint means capturing again on a new build computer, while a failed
draft command names its own cause to fix. If a declared secret was used,
automatic drafting is withheld: write the task manually and export it.
When `draft.files` is empty,
`draft.notes` says why:
- `no_change`: nothing was saved between `seed` and `end`. Capture again
on a new build computer, and save before marking `end`. When the app
keeps the task's state only on screen, such as a calculator's result,
judge the screen instead (see Judge the screen).
- `unowned_changes` with `no_document`: the app saved your document
where REA did not count it as the app's. Its `files` list what changed,
with their roles; the document is among them. Close the computer and
capture again on a new one with that path in `state_paths`; the export
refuses a check on a file outside the owned paths.
- `uncheckable_changes`: the app saved the change in dconf, as gedit does
its preferences, and no check reads dconf. Saving again does not help:
choose a change the app saves in a file, and capture again on a new
build computer, or judge the screen (see Judge the screen).
- `unreadable_changes`: a dconf database changed but REA could not read
it; `error` says why. This is not evidence the app saved there: report
the error rather than changing the task.
A note with a `file` says why that file's suggestions are thin:
- `by_position`: only position names what changed; its `elements` lack
a naming attribute. Name a record that keeps its fields as child
elements by one of them, as Osmo's contact by
`[name=contact][>first_name=Delphine]`, a JSON record by a field
inside it, `[>data/Title=…]` (`~1` for the `/` inside a pointer), or
an element by an id its child carries, `[>object@id=…]`; count records
with `member_count`, `matching` `[name=contact]`; otherwise check an
ancestor's text, or give the element an id in the app and capture again.
- `view_state_only`: every change is view state, a renumbered id or a
time the app stamps, and its `pointers` are the checks kept. The edit
was likely not saved: capture again and save it before `end`.
- `long_text`: the element's text is too long to check whole; check a
phrase in it with `text_contains`.
- `cut_view` or `unreadable_view`: REA's view holds only part of the
file, or none a check can read, such as a binary format (step 3). For
a binary file, read it with a reader (see Read a binary file with a
reader).
## Write the task
@@ -156,20 +424,49 @@ Write `{"name", "prompt", "checks"}` from the draft and what you did.
- `name`: lowercase letters, digits and hyphens, not `smoke`.
- `prompt`: what the requester wants, in their words and the app's terms,
naming the document as a user would and ending with saving it: "Change the
poster's headline in Documents/poster.svg to Summer Bake Sale and save
it." Never say how the file stores it, and never give the checks.
starting with the app's name, naming the document as a user would and
ending with saving it: "In Inkscape, change the poster's headline in
Documents/poster.svg to Summer Bake Sale and save it." Name the app: the
solving agent's own shell cannot see the computer's files, and the app's
name sends it to the screen. Leave saving out for an app that saves on its own, after every change
or a few seconds after the last one, such as Osmo or Gnote: grading waits
until the app's files have held for 3 s, so the solving agent need not
wait for the save. A save more than 3 s after the agent stops is still
missed; name such an app in the report. Never say how the file stores it,
and never give the checks.
- Checks are file-based: content checks that prove the edit, never only that
a file exists or changed. Start from the suggestions; keep those that say
what the user did and drop what follows from how the app saves.
- Compare exact values, so a typo or a wrong number fails.
- Read each file's `values` before writing checks: every value the change
added, changed and removed, with `before` and `after` (an uncut scalar, or
a preview cut at 600 characters) at the pointer a check names it by. Copy
the pointer. Copy `after` into `value` only when it is an uncut scalar: a
string without a trailing `…`, a number, or a boolean. Compact XML and a
JSON array or object are preview strings, so a `value_equals` check needs
the structured value from the file's view, and element text uses
`text_equals` or `text_contains`.
Only XML files, archives, JSON and key files have values: a text file's
or SQLite database's `change` already lists its lines and rows.
`refers_to` says what a number or id stands for, such as `category="44"`
naming `<cat key="44" name="Groceries"/>`, or a new KMyMoney
transaction's splits naming their account and payee; use it for the
prompt's words. `alternatives` gives a changed value's pointer by the
element's other names, such as a label beside an id, to pick another key
without another export.
Skip entries whose `note` is `by_position` (no check can use that
pointer) or noise (`view_state`, `renumbered`, `volatile`,
`timestamp`, `upkeep`, `layout`). `values_cut` means a limit left some out.
- Select elements by what they hold, never by position: SVG text by id,
`/root/children/[name=g][@inkscape:label=Layer 1]/children/[name=text][@id=headline]/children/[name=tspan]/children/0`,
or an ODF paragraph by style,
`/entries/[name=content.xml]/view/root/children/[name=office:body]/children/[name=office:text]/children/[name=text:p][@text:style-name=Title]/children/0`.
A selector must match exactly one element, so give the target a unique id
or style in the seed. The draft may suggest positional pointers; rewrite
them. Only an element's text is read by position, as `children/0`.
or style in the seed. The draft's pointers already do this: a name-like
attribute such as Scribus's `ANNAME` before a coordinate, and two
attributes together where one is not enough, as a spreadsheet cell's
`[@Col=3][@Row=2]`. Only an element's text is read by position, as
`children/0`.
- When an app may split an element's text into runs, check it whole:
`text_equals` (or `text_contains` for a value inside a sentence) on the
element compares all its text, however it is split. Add
@@ -178,15 +475,48 @@ Write `{"name", "prompt", "checks"}` from the draft and what you did.
`{"kind": "text_contains", "file": "Documents/memo.abw", "pointer": "/root/children/[name=section]/children/[name=p][@xid=6]", "value": "at 3:30 PM"}`.
Point a text check at the paragraph or another element the edit keeps,
never at a run such as AbiWord's `[name=c]`: a reopened document splits
the text into several runs. The draft lists only what changed; to name an
unchanged element, such as another paragraph's `xid`, use the app's usual
numbering and let the export confirm it, or read it in the exported
bundle's `envs/<env>/seed/`.
the text into several runs. The draft lists only what changed; an
unchanged element is in `draft.guards` when it is a like sibling of a
changed one, and otherwise use the app's usual numbering, such as another
paragraph's `xid`, and let the export confirm it.
- In an ODS spreadsheet no attribute names a row: the draft names it by its
label cell, `[name=table:table-row][>table:table-cell=February]`. Where no
cell names it alone, name the sheet in the seed, and check its whole
text: `text_equals` on
`/entries/[name=content.xml]/view/root/children/[name=office:body]/children/[name=office:spreadsheet]/children/[name=table:table][@table:name=Q1 Sales]`,
or a stretch of it with `text_contains`. Cell texts join with nothing
between, so a row reads `February23100`.
- For a line added to free text, such as an item on a note's list, the
draft compares the whole text with `text_equals`. This rejects longer or
negated items, but can reject a correct edit with different ordering or
spacing. Report that limitation when the task permits such variations.
- For a note placed by its own `x` and `y`, such as Xournal++'s `<text>`
on a layer, the draft checks its text on the layer with `text_contains`,
which passes wherever the user puts it, and guards each note it kept.
- Some apps keep text in an attribute, one element per run, such as
Scribus's `<ITEXT CH=...>`: add `"text_attribute": "CH"` to `text_equals`
or `text_contains` on the frame,
`/root/children/[name=DOCUMENT]/children/[name=PAGEOBJECT][@ANNAME=Headline]`,
to read its runs' values joined.
- When the draft shows no values or no checks, a scratch export can expose
`envs/<env>/seed/` only after the task has at least one valid check: it must
pass on the captured end state and fail on the seed. Before the first
successful export, use `act_on_build_computer` to open the saved file in an
available GUI text editor or viewer and inspect its actual representation
without changing it. Use the visible saved content and the task's edit to
write a check; an export refusal can also name the end state's value, such
as `is "44", not "1"`. If the file cannot be inspected or expressed by a
supported check, report the limitation instead of guessing a check.
- Where easy, add one check that the rest is untouched, such as another
text's value the edit must leave alone. It is the one unchanged value
worth checking; it passes on the seed too, which is fine, since the export
needs only one check to fail there.
- Give `value_equals` a `tolerance` for a number the app writes as text.
text's value the edit must leave alone. `draft.guards` offers them at
their seed values, which the end holds too: a field on the nearest like
siblings, one the user sets, such as Planner's `work`, before a default
they all share; the text an addition kept; a text file's lines beside its
new one. Copy one or two into `checks`; they pass on the seed, which is
fine, since the export needs only one check to fail there.
- The draft suggests a decimal the app writes as text, such as `146.83`,
as a number with `tolerance: 0.001`; keep the tolerance for any number
you check that way.
- When the draft shows an XML document's changes as `lines`, REA read it
as text, for example because its DOCTYPE declares entities. Selectors are
impossible there, and `line_count` with `contains` only approximates a
@@ -200,6 +530,124 @@ Write `{"name", "prompt", "checks"}` from the draft and what you did.
The kinds and pointer rules are in
[the desktop tasks section](environments.md#pick-the-checks).
### Read a binary file with a reader
When the draft notes `unreadable_view` on a binary document, add a reader to
the task: the app's own headless command, which REA runs in the computer on a
private copy of the file, and whose output a check reads instead of the file.
Write it in the app's scripting mode, print each fact on a line starting
with `REA ` (with the space), and name the copy `{file}`:
- GIMP `.xcf`, layer names, as `lines`:
```json
{
"id": "layers",
"file": "Documents/poster.xcf",
"argv": ["gimp-console-2.10", "-i", "-d", "-f", "-b", "-"],
"stdin": "(let ((image (car (gimp-file-load RUN-NONINTERACTIVE \"{file}\" \"{file}\")))) (for-each (lambda (layer) (display \"\\nREA layer \") (display (car (gimp-item-get-name layer)))) (vector->list (cadr (gimp-image-get-layers image)))) (newline))\n(gimp-quit 0)\n",
"output": "lines"
}
```
checked with `{"kind": "lines_present", "file": "Documents/poster.xcf", "reader": "layers", "lines": ["layer Summer Sale"]}`.
Script-Fu's prompt `ts> ` starts a line, so print a newline before each
marked line, as `\nREA` does. A text layer's text is
`(car (gimp-text-layer-get-text layer))`.
- Blender `.blend`, objects with their type and location, as `json`:
```json
{
"id": "objects",
"file": "Documents/scene.blend",
"argv": [
"blender",
"-b",
"--factory-startup",
"{file}",
"--python-expr",
"import bpy, json; print('REA ' + json.dumps({o.name: {'type': o.type, 'location': [round(v, 4) for v in o.location]} for o in bpy.data.objects}, sort_keys=True))"
],
"output": "json"
}
```
checked with `{"kind": "value_equals", "file": "Documents/scene.blend", "reader": "objects", "pointer": "/Crate/location/0", "value": 2, "tolerance": 0.001}`.
Print every value a check compares as a number or string a check can
name, rounded where the app stores floats.
Blender 4 shows its Quick Setup splash at every launch until its
preferences are saved: with `.config/blender` in `state_paths`, confirm
Quick Setup with Continue, save the preferences (Edit → Preferences, then
Save Preferences in the menu at its bottom left), and read a probe
checkpoint's `changed_files` for `.config/blender/4.0/config/userpref.blend`
before `seed`, so solves start on the scene. Blender often takes the first click on a
menu or a dialog's button only to focus it: click again.
- A format LibreOffice opens but REA cannot read, such as a legacy `.xls`,
converted with `--convert-to`:
```json
{
"id": "cells",
"file": "Documents/budget.xls",
"argv": [
"sh",
"-c",
"soffice --headless --convert-to csv --outdir out \"$1\" >/dev/null && sed 's/^/REA /' out/*.csv",
"sh",
"{file}"
],
"output": "lines",
"timeout_s": 120
}
```
Pass `{file}` to `sh -c` as an argument, as here, rather than inside the
script.
The reader runs without the display, in a fresh home with the app's default
settings, so use the app's headless or batch mode; set `display: true` only
for an app that has none. It must exit 0 within `timeout_s` (60 s by
default, at most 300) and print at most 1 MiB. Pick facts the change sets and
the near miss gets wrong, such as a name or a number, not the app's whole
output.
Give the task the reader in `readers`, and each check through it `reader`
and the reader's `file`. `json` readers serve `value_equals`, `value_absent`
and `member_count`; `lines` readers `lines_present`, `lines_absent` and
`line_count`. The export runs the reader in the build computer on the seed
and the end: when a check through it fails on the end, the refusal shows
what the reader printed, and a reader that fails shows its error and the end
of its stderr. Fix the reader or the check from that and export again.
### Judge the screen
Only when no file shows the change, as when the draft notes `no_change`
because the app keeps its state on screen, write the task's checks as
screen judges: `{"id": "shown", "kind": "screen_judge", "question": "Does the
calculator's display show 8.568?"}`. A model, the judge, answers the question
on a screenshot three times, and the check passes when most answers are yes.
- REA keeps a screenshot at each checkpoint. Mark `seed` with the screen
showing the state before the task, where the answer is no, and `end` with
the change showing, where it is yes: the bundle ships both as the judge's
examples.
- Ask about what the change makes visible, with exact values, so the near
miss is a no: a result, a label, a selected item. Avoid what a window
moved or a cursor blinking can change.
- The prompt asks to leave the result showing, since the judge sees only
the screen when the agent stops.
- A task with screen judges holds only screen judges and no readers. The
export refuses one when a file shows the change, and checks none of its
questions: the witness does, running the bundle's own judge with the
runner's model endpoint (`LITELLM_BASE_URL` and `LITELLM_API_KEY`, or
`[model]` in `.agentenv/config.toml`) on a fresh screenshot at each stage.
Without an endpoint the witness's check fails: say what to set and stop.
- The judge's model is `[model.roles] judge`, else `[model] default`, else
`anthropic/claude-sonnet-5-5`. `agent-env run --judge-model` does not
reach it. Each grade costs about $0.02.
## Export
`export_build_environment` with `task` and `directory`, the absolute path of
@@ -211,10 +659,36 @@ unless at least one check fails on the seed and every check passes at the
end, and says why, such as a pointer that names nothing at the end. A
check that the rest is untouched passes on the seed too, which is fine. On
a refusal, fix the task and export again, into another folder if that one
is no longer empty. Keep
is no longer empty. A refusal naming a secret's handle means a file of the
bundle holds that secret, most often an app's sign-in or licence state in
the seed: do not work around it, but report it and stop. Keep
`seed_files`, `scrubbed_files`, `unscrubbed_files` and `limitations` for the
report.
The limitations name the folders the app wrote that the bundle neither owns
nor seeds, such as `~/.config/MuseScore`, so the app starts without them:
expect its first-run wizard, a tour or a "restore session?" question at every
boot. If the witness shows one, capture again on a new build computer with
those folders in `state_paths`, and dismiss the dialogs before `seed`. Lock
files the app holds while it runs, such as LibreOffice's `.lock` and
`.~lock.<name>#`, GnuCash's `<book>.LCK` or Grisbi's `.<file>.lock`, are
left out of the seed and listed after "Left out of the seed". An app can
still start fine yet refuse every save when a lock was seeded, so close the
document before `seed` where the app lets you (apps other than LibreOffice,
such as Rosegarden, also write `.~lock.<name>#` and autosaves beside a
document, and closing it covers them too), and treat "file is locked"
on a save in the witness as a seeded lock: delete it from the bundle's seed
and witness again in a new computer. In LibreOffice, own the profile
(`state_paths: [".config/libreoffice"]`) for a clean boot, and close the
document before `seed`, then reopen it from Recent Documents to make the
change: the export also leaves out the recovery list LibreOffice writes while
a document is open, which would start the bundle into document recovery. A
limitation naming `~/.config/dconf/user` as unread means the app's dconf
settings, such as a first-run tip you turned off, are not seeded: capture
again on a new build computer. The limitations also name seeded WebKit,
Chromium or QtWebEngine storage and caches; when the witness's boot is clean,
list them in the report.
Keep the build computer open until the witness holds: a task fix exports
again from it.
@@ -226,17 +700,27 @@ check between stages to steer the edit: a solving agent never sees the
checks. Give every `check_build_task` the task exactly as exported.
1. `start_build_computer` with
`{"source": {"kind": "bundle", "path": "<bundle>"}}`. The app starts
`{"source": {"kind": "bundle", "path": "<bundle>"}}`, adding
`"settings": {"<variable>": "<handle>"}` for each of the export's
`withheld_files`, or the deploy is refused for want of them, and agentenv
keeps that bundle's build failed, so start from a fresh copy of it. The app starts
with the seed's files in place and opens the seed's document when the
seed holds exactly one and the app takes a file. When the export's
`limitations` say it opens no document, open it from the prompt's path,
as a solving agent would. Take a `wait` screenshot first, since the
desktop may not have drawn yet.
desktop may not have drawn yet. When the start fails because the
computer never got ready, and its error names lock files in the bundle's
seed, delete them from the bundle and start again.
2. `check_build_task` with `stage: "seed"` and `directory`, the absolute
path of a new or empty folder for the record. A check must fail.
Recording starts. Later stages take no `directory`.
3. Do the task from the prompt with `act_on_build_computer` and save.
`check_build_task` with `stage: "after_edit"`: every check must pass.
Each check waits until the app's files have held for 3 s, as the
bundle's verifier does, so an app that saves on its own needs no wait of
yours. A result with `settled: false` means the files were still
changing at the 15 s bound, and `read_cut: true` that a slow read was
still running there.
4. Make a near miss on top of it: a plausible wrong edit, such as a typo or
a wrong number, and save. `check_build_task` with `stage: "near_miss"`:
a check must fail.
@@ -262,14 +746,17 @@ Stop after three witnesses and report what still fails.
## Solver runs
Only if the requester asked for them. If they wanted to review the task
first, show them its prompt and checks and wait for their approval. Then run
the bundle within the budget, one run at a time, with the runner
`REA_AGENT_ENV_COMMAND` names:
Only if the requester asked for them, or by the headless default above. If
they wanted to review the task first, show them its prompt and checks and
wait for their approval. Then run the bundle within the budget, one run at a
time, with `REA_AGENT_ENV_COMMAND`'s runner, or else `agent-env` on PATH:
`agent-env run <bundle> --task <name> --agent claude-code --model <model>`.
Count runs reported `passed`. A run `scored below 1` is a miss; one reported
`failed` did not finish, so run it again if the budget allows instead of
counting it. Never run past the budget.
The runner needs a model endpoint in your shell: `LITELLM_BASE_URL` and
`LITELLM_API_KEY`, or `base_url` and `api_key` under `[model]` in
`.agentenv/config.toml`. When a run says no model endpoint is set, tell the
person what to set and stop. Count runs reported `passed`. A run
`scored below 1` is a miss; one reported `failed` did not finish, so run it
again if the budget allows instead of counting it. Never run past the budget.
## Close and report
@@ -281,12 +768,15 @@ Report:
- the bundle path and the environment name;
- the task's name and prompt;
- each check, and why it proves the edit and fails the near miss;
- each check, and why it proves the edit and fails the near miss, and each
reader's command;
- each witness stage with its result, the verdict, and the paths of
`witness.json` and the recording;
- the seed's contents: `seed_files` and what each holds;
- `scrubbed_files` and `unscrubbed_files`; an unscrubbed file still names
the host or user, so it needs review before sharing;
the host or user, so it needs review before sharing. `recompressed_files`
are gzip seeds whose headers were cleared, their content unchanged: give
their count;
- limitations: the capture's, the export's and anything you could not do;
- solver runs, if any: the model, the runs and the passes;
- the build time and the questions you asked.
@@ -308,14 +308,27 @@ Run `rea describe-desktop-application-task CAPTURE --format json`. Read:
and last version, with its `role`, the `baseline` and `final` versions and
the net `change`. Text changes list each added and removed line once, and
`line_counts` gives lines found at both ends whose count changed.
- `values` in each of those files: what the change added, changed and
removed, `before` and `after`, at the pointer a check names it by, with
`refers_to` naming the element a key such as `category="44"` stands for.
Skip entries noted `by_position` or as noise. Only XML files, archives,
JSON and key files have values: a text file's or database's change
already lists its lines and rows.
- `task`: a draft whose `checks` are suggestions from the net change of the
documents the user worked on, or of the app's own state when no document
changed.
- `guards`: optional checks that the rest kept its seed values, such as a
like sibling's field or a text file's neighbouring lines; add one or two
to show the rest is untouched.
- `notes`: why `files` is empty, or why a file's suggestions are thin, such
as `by_position` when no attribute names the changed element.
### Write the prompt
Say what the user wants done, in their words and the app's terms: "Add buy
milk to my to-do list and save it". Never say how the file stores it: no
Say what the user wants done, in their words and the app's terms, naming the
app: "In Mousepad, add buy milk to my to-do list and save it". A solving
agent's own shell cannot see the computer's files; the app's name sends it to
the screen. Never say how the file stores it: no
paths the user would not name, line formats, XML, keys or SQL, and never the
checks. Replace the draft's placeholder; the export refuses it.
@@ -346,13 +359,18 @@ document saved as a zip archive, such as FreeCAD's `.FCStd`, reads as its
entries: point into an entry's view, and name array members by selector
rather than position, as
`/entries/[name=Document.xml]/view/root/children/[name=Object][@name=Hole]`,
so the check survives an app version that writes them in another order. Give
so the check survives an app version that writes them in another order. A
gzip-compressed document, such as Gnumeric's `.gnumeric`, reads as the
document inside: point into it as into the same document uncompressed. Give
`value_equals` a `tolerance` to compare a number the app writes as text, such
as `"5.0000000000000000"`, with a number. Check what the user wrote in a
document with `text_equals` on its paragraph element, not `value_equals` on a
text node: apps such as AbiWord and Writer split a paragraph into runs as they
save, so its first text node holds only part of it; use `text_contains` for a
value within a sentence, such as a time. The
value within a sentence, such as a time. A binary document, such as GIMP's
`.xcf`, has no view: give the task a `readers` entry, the app's own headless
command printing `REA ` lines, and a check naming it in `reader`, as
[desktop builds](desktop-build.md#read-a-binary-file-with-a-reader) shows. The
[desktop application tasks](https://github.com/morluto/rea/blob/main/docs/desktop-application-tasks.md)
guide has the exact rules.
@@ -374,5 +392,7 @@ user's to choose.
Tell the user the task's name, prompt and checks, and how to measure a solve
rate: run `agent-env run DIRECTORY --task NAME --agent claude-code` with
`--model MODEL` three times and count the runs reported `passed`. Do not run
`--model MODEL` three times and count the runs reported `passed`. The runs
need a model endpoint: `LITELLM_BASE_URL` and `LITELLM_API_KEY`, or
`base_url` and `api_key` under `[model]` in `.agentenv/config.toml`. Do not run
agents unless asked. The bundle's seed is the user's real data: keep it local.
@@ -149,6 +149,20 @@ table or overlay. Bound snapshots, loaded IAT contents, and export-forward
resolution remain unobserved. See
[PE import and delay-load tables](https://github.com/morluto/rea/blob/main/docs/pe-imports.md).
## Windows Shell Link shortcuts
Use `inspect_windows_shortcut` for an explicit local `.lnk` file when the
question concerns the recorded target path, arguments, working directory, icon
location, volume serial, network share names, ExtraData blocks, or Tracker
droid identifiers. No `open_binary`, Windows SDK, COM, or target execution is
required. The CLI equivalent is `inspect-windows-shortcut PATH`. Preserve
artifact SHA-256, FILETIME raw decimals, IDList type bytes, and ExtraData
signatures. Unknown IDList items and ExtraData signatures remain raw with
SHA-256; they are not guessed. Version-1 UUID MAC and timestamp values are
labelled derived. A missing optional section is observed absence of that
structure. See
[Windows Shell Link shortcuts](https://github.com/morluto/rea/blob/main/docs/guides/native/windows-shortcut.md).
## PE TLS callbacks and load configuration
Use `inspect_pe_load_config` for an explicit local PE32/PE32+ image when the
@@ -185,6 +199,36 @@ absence of those declarations, not proof the image never carried notes in
another container. See
[ELF note tables](https://github.com/morluto/rea/blob/main/docs/elf-notes.md).
## ELF and Mach-O initializer functions
Use `inspect_native_initializers` for an explicit local ELF or Mach-O image
when the question is which functions run before `main` or at exit: ELF
`DT_PREINIT_ARRAY`, `DT_INIT`, `DT_INIT_ARRAY`, `DT_FINI`, `DT_FINI_ARRAY` and
legacy `.ctors`/`.dtors`, or Mach-O `__mod_init_func`, `__init_offsets` and
`__mod_term_func`. Pass `architecture` for a universal Mach-O. The CLI
equivalent is `inspect-native-initializers PATH`. PIE slots are resolved
through RELATIVE, RELR and section relocations, and Mach-O slots through
chained fixups. Keep each entry's `resolution`: `unresolved` means the value was
not established, and `unresolved_import` names an external symbol. Page with
`offset` and `limit`. See
[ELF and Mach-O initializer functions](https://github.com/morluto/rea/blob/main/docs/guides/native/native-initializers.md).
## ELF unwind function ranges
Use `inspect_elf_unwind_ranges` for an explicit local ELF32/ELF64 image when
the question concerns function starts and lengths that survive `strip`, which
functions have an LSDA, or which ranges have no exact symbol. No
`open_binary` or target execution is required. The CLI equivalent is
`inspect-elf-unwind-ranges PATH`. Preserve artifact SHA-256, FDE start and
end, containing section, exact symbol name, CIE index, LSDA, and personality.
Page later ranges with `offset` and `limit`. A missing `.eh_frame` is
observed absence of that declaration and of `PT_GNU_EH_FRAME`, not proof the
image has no functions. Header disagreement is a limitation and does not drop
decoded ranges. `.debug_frame` is reported present or absent and is not
decoded. CFA instructions are counted and not evaluated. Indirect EH pointers
are not dereferenced. See
[ELF unwind function ranges](https://github.com/morluto/rea/blob/main/docs/guides/native/elf-unwind-ranges.md).
## Apple IPS crash reports
Use `inspect_apple_ips` for an explicit local Apple `.ips` file when the
@@ -216,6 +260,27 @@ container. gzip, xz, and zstd whole-file containers are unsupported and name
decompress into a separate file, then call `inspect_kernel_module` on that file. See
[Linux kernel modules](https://github.com/morluto/rea/blob/main/docs/kernel-modules.md).
## Linux kernel build config
Use `inspect_kernel_build_config` for an explicit local kernel image (`vmlinux`
ELF, raw arm64 `Image`, x86 `bzImage`/`zImage`, or `configs.ko`) when the
question is which kernel version it is or how it was configured. No
`open_binary`, Linux host, or `extract-ikconfig` is required. The CLI
equivalent is `inspect-kernel-build-config PATH`; pass `name` for one exact
`CONFIG_*` option and `offset`/`limit` to page the rest. Preserve the banner
version, builder, and compiler, the config SHA-256 and option count, and each
entry's value kind (`y`, `m`, `string`, `number`, `not_set`). A config is
accepted only when `IKCFG_ST` is immediately followed by a valid gzip member
and `IKCFG_ED`, so an ordinary `IKCFG_ST` string is not a config. Offsets with
`space: "inflated_payload"` are positions in an inflated bzImage payload, not
file offsets. An absent config describes only the searched bytes; the kernel
may have been built without `CONFIG_IKCONFIG` or with it as a module. Truncated
payloads are incomplete, not absent. A framed blob that does not decode, has a
bad CRC, or holds non-config text is `malformed`, not absent. xz, lz4, lzma, zstd, bzip2, and lzo
payloads are unsupported and name `external_decompression`: decompress with an
external utility, then call `inspect_kernel_build_config` on the result. See
[Linux kernel build config](https://github.com/morluto/rea/blob/main/docs/guides/native/kernel-build-config.md).
## CPython pyc files
Use `inspect_python_pyc` for an explicit local CPython 3.7–3.13 `.pyc` when the
@@ -843,3 +908,24 @@ Layout labels describe record shapes, not a detected compiler version; unknown
or ambiguous layouts are unsupported. Bytecode is retained, not decoded, and the
executable is never run. See
[Bun standalone executables](https://github.com/morluto/rea/blob/main/docs/bun-standalone.md).
## Deno compile executables
A `deno compile` executable stores its application in a Mach-O `__SUI,d3n0l4nd`
section, an Intel Mach-O `<~sui-data~>` trailer, an ELF `SUI` note of type
`0x53554901`, or a PE `RT_RCDATA` resource named `D3N0L4ND`.
`open_binary` then `inspect_artifact` reports root format `deno-standalone`
with the carrier, entry point, recorded options, and one occurrence per virtual
file, including size and SHA-256. Transpiled output, CJS export analysis, and
source maps are separate occurrences with the file's `index` and their own
`role`. They normally use a `.deno-*` suffix on the file path and move to an
indexed path on a collision, so use the reported `logical_path`. Symlink targets
stay recorded path parts. A virtual filesystem that cannot be listed leaves
coverage unknown.
Environment-file values and CA certificate bytes are retained in local Evidence
with their counts and byte lengths. The npm snapshot length is reported and not
decoded. `extract-artifact` writes
stored files through the safe output tree; route extracted JavaScript to
`analyze_javascript_application`. Other layouts are unsupported, and the
executable is never run. See
[Deno compile executables](https://github.com/morluto/rea/blob/main/docs/deno-standalone.md).
@@ -41,6 +41,12 @@ behavior unknown. Record truncation, unmatched breakpoints, changed target
identity and cleanup uncertainty as limitations, rather than treating no retained
event as proof that the behavior never occurs.
For same-session MCP comparisons, pass each capture inline or reuse it as
`{"kind":"retained-evidence","evidence_id":"ev_..."}`. Default comparison
keeps capture-local timing as provenance without treating scheduler or observer
latency as a behavior change; use an exact `trace_spec` event when timing is part
of the analyst question.
Detailed contracts and prerequisites: [Frida](https://github.com/morluto/rea/blob/main/docs/guides/runtime/frida-instrumentation.md),
[GDB/Rizin/Cutter](https://github.com/morluto/rea/blob/main/docs/reverse-engineering-tools.md),
[process capture](https://github.com/morluto/rea/blob/main/docs/guides/runtime/process-capture.md),
+1
View File
@@ -924,6 +924,7 @@ jobs:
tests/process-global/filesystemSnapshotFallbackCancellation.test.ts
tests/boundary/filesystem/typescriptCompiler.test.ts
tests/boundary/filesystem/releaseProposal.test.ts
tests/acceptance/byteEntropyWindowsIdentity.test.ts
tests/boundary/filesystem/binaryTarget.test.ts
src/contracts/sessionPathInputs.test.ts
tests/boundary/filesystem/directAnalysisSnapshotReplay.test.ts
@@ -95,3 +95,31 @@ jobs:
decode cortex ARM:LE:32:Cortex mrs/4/msp bx/2/lr
decode v8m ARM:LE:32:v8-m mrs/4/msplim bx/2/lr
decode xtensa Xtensa:LE:32:default entry/3/a1 retw.n/2
# A call through a writable slot keeps Ghidra's recorded target as an
# observed callee while callee coverage stays partial; a direct call is
# the complete control. The source-owned x86-64 bytes are never executed.
- name: Keep computed-call targets non-exhaustive in callee coverage
shell: bash
run: |
java_home_variable="JAVA_HOME_${GHIDRA_JAVA_MAJOR}_X64"
export JAVA_HOME="${!java_home_variable}"
probe_root="${RUNNER_TEMP}/rea-computed-call"
mkdir -p "${probe_root}/project"
{
printf '\270\001\000\000\000\303\314\314' # 0x1000: mov eax, 1; ret
printf '\270\002\000\000\000\303\314\314' # 0x1008: mov eax, 2; ret
printf '\377\025\052\000\000\000\303\314' # 0x1010: call [rip + 0x2a]; ret
printf '\377\320\303\314\314\314\314\314' # 0x1018: call rax; ret
printf '\350\333\377\377\377\303\314\314' # 0x1020: call 0x1000; ret
printf '\314%.0s' $(seq 24) # 0x1028: int3 padding
printf '\000\020\000\000\000\000\000\000' # 0x1040: slot = 0x1000
} > "${probe_root}/computed-call.bin"
test "$(wc -c < "${probe_root}/computed-call.bin")" -eq 72
timeout 180s "${GHIDRA_INSTALL_DIR}/support/analyzeHeadless" "${probe_root}/project" ComputedCall \
-import "${probe_root}/computed-call.bin" -loader BinaryLoader -loader-baseAddr 0x1000 \
-processor x86:LE:64:default -noanalysis -readOnly -deleteProject \
-scriptPath "${GITHUB_WORKSPACE}/tests/conformance/ghidra;${GITHUB_WORKSPACE}/bridge/ghidra" \
-postScript ReaComputedCallCoverageProbe.java "${GITHUB_WORKSPACE}/bridge/ghidra" \
> "${probe_root}/output.log" 2>&1 || { cat "${probe_root}/output.log"; exit 1; }
cat "${probe_root}/output.log"
grep -F 'REA_COMPUTED_CALL_COVERAGE_OK slot=observed-complete-discovery-unknown register=partial direct=complete callers=discovery-unknown' "${probe_root}/output.log"
+13
View File
@@ -130,6 +130,19 @@ status checks alongside its existing checks. Deploy the workflow to each
protected target branch before requiring it there. The workflow reads PR
metadata using trusted default-branch code and writes only a commit status.
When an open PR may overlap another open change or a recently landed fix, note
the related PR, issue, or commit in the description or a comment as soon as the
overlap is known. Prefer one clear pointer over repeated status updates.
If an overlapping change merges while a PR awaits review, link that commit on
the open PR and state what remains useful. Rebase or otherwise align with the
current base when the remaining work is still wanted, narrow the PR to the
uncovered portion, or close it when the change is fully superseded. Keep the
description and validation current after that update. Maintainers may also note
the expected disposition (rebase, narrow, or close) when they land or recognize
an overlapping fix. Readiness still does not grant merge permission or a review
date.
Maintainers may return a PR to the author or close it when the problem is
unsupported, validation is missing, or the owner cannot explain the change.
Contributors are responsible for completing this work before requesting review.
+9 -1
View File
@@ -1,7 +1,7 @@
<div align="center">
**English** · [简体中文](docs/readme/README_zh.md) · [繁體中文](docs/readme/README_zh-TW.md) · [日本語](docs/readme/README_ja.md) · [한국어](docs/readme/README_ko.md) · [Türkçe](docs/readme/README_tr.md) · [Русский](docs/readme/README_ru.md) · [Tiếng Việt](docs/readme/README_vi.md) · [ไทย](docs/readme/README_th.md) · [Deutsch](docs/readme/README_de.md) · [Español](docs/readme/README_es.md) · [Français](docs/readme/README_fr.md) · [Українська](docs/readme/README_uk.md) · [Polski](docs/readme/README_pl.md) · [Português (Brasil)](docs/readme/README_pt-BR.md) · [العربية](docs/readme/README_ar.md) · [فارسی](docs/readme/README_fa.md) · [Bahasa Indonesia](docs/readme/README_id.md) · [Italiano](docs/readme/README_it.md)
· [Ελληνικά](docs/readme/README_el.md) · [മലയാളം](docs/readme/README_ml.md) · [Roman Urdu](docs/readme/README_ur-Latn.md) · [Română](docs/readme/README_ro.md)
· [Ελληνικά](docs/readme/README_el.md) · [മലയാളം](docs/readme/README_ml.md) · [Roman Urdu](docs/readme/README_ur-Latn.md) · [Română](docs/readme/README_ro.md) · [Български](docs/readme/README_bg.md)
# REA: Reverse Engineer Anything
@@ -204,6 +204,7 @@ Additional tools and host support depend on the target:
| Rust binaries | Embedded cargo-auditable crate names, versions, sources and dependency edges | Built-in static ELF/PE/thin Mach-O inspection; [Rust binaries](docs/rust-binaries.md) |
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](docs/pe-certificates.md) |
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](docs/pe-imports.md) |
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](docs/guides/native/windows-shortcut.md) |
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](docs/elf-notes.md) |
| Binary hardening | PIE, NX, RELRO, CFG and related header flags for ELF, PE and Mach-O | Built-in static header inspection; [binary hardening](docs/binary-hardening.md) |
| Apple IPS crashes | .ips metadata, threads, images, registers and documented crash classes | Built-in static JSON inspection; [Apple IPS](docs/apple-ips.md) |
@@ -230,6 +231,7 @@ Additional tools and host support depend on the target:
| Packages and resources | File inventories, digests, plists, Apple bundle anatomy and extracted resources | [Artifact and JavaScript guide](docs/guides/javascript/javascript-artifact-reconstruction.md), [Apple applications](docs/guides/apple/apple-application-analysis.md) |
| Process behavior | Terminal output, interactions, exit and filesystem observations, and run comparisons | Linux/macOS with a native PTY; [process capture](docs/guides/runtime/process-capture.md) |
| PyInstaller executables | CArchive members, Python version, entry scripts and extracted bytecode | None (static only); [Python packaged applications](docs/python-packaged-applications.md) |
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | None (static only); [Deno compile executables](docs/deno-standalone.md) |
Static JavaScript and .NET inspection read the supplied files without running
the application. Runtime capture runs or interacts with the selected target
@@ -335,6 +337,12 @@ REA exports a runnable environment with a basic test to check that it starts and
[Environment reference](docs/agent-environments.md) ·
[Watch the demo on X](https://x.com/reatools/status/2112574822584918075?s=20)
### Desktop app environments
REA can also build an environment of a Linux desktop app, which an agent uses through screenshots, the mouse and the keyboard. From a one-line request, such as "Build me a Gnote environment where the agent adds olive oil to the shopping list note", your agent installs the app on a local build computer, writes the task, exports the environment and checks the task in a fresh computer. The machine that builds it needs Linux on amd64 or arm64, Docker and the agentenv framework version the guide pins.
[Set up desktop app environments](docs/desktop-build-computer.md)
## FAQ
<details>
+255 -12
View File
@@ -1,7 +1,9 @@
"""Run REA inside an agentenv build computer for REA on the host: capture the app, draft its task and export it.
REA sends this file's source through the computer's ``computer-exec/v1`` route as
``python3 -I -c <source> <command> <JSON arguments>``; each command prints one JSON line and exits. ``start``
``python3 -I -c <source> <command> <JSON arguments>``. JSON that would exceed the bytes Linux
passes as one string travels as several arguments, which this file joins before parsing. Each command prints
one JSON line and exits. ``start``
leaves the capture running on its own: its stdin is a FIFO it holds open for reading and writing, so it never
sees the end of its input, and ``mark`` and ``stop`` write their requests there and wait for the capture's own
acknowledgement on its progress log. A small shell around the capture writes its exit status to a file, the
@@ -91,6 +93,13 @@ def _exit_code(capture: str):
return None
def _ended(capture: str, code: int) -> dict:
"""A capture that has exited: its status, the end of its progress log and its output's size, which REA reads
whole for the Evidence or failure it ended with, whichever step was waiting on it."""
return {"exited": code, "progress": _tail(os.path.join(capture, "progress.log")),
"output_bytes": os.path.getsize(os.path.join(capture, "capture.out"))}
def _event_line(path: str, offset: int, kinds: set, name):
"""The first progress line after ``offset`` whose event is of one of ``kinds``, for ``name`` when given."""
try:
@@ -119,17 +128,49 @@ def _wait(capture: str, offset: int, kinds: set, name, timeout: float) -> dict:
return {"line": line}
code = _exit_code(capture)
if code is not None:
return {"exited": code, "progress": _tail(log), "output": _tail(os.path.join(capture, "capture.out"))}
return _ended(capture, code)
if time.monotonic() > deadline:
return {"timed_out": True, "progress": _tail(log)}
time.sleep(POLL_S)
def _within(path: str, folder: str) -> bool:
return path == folder or path.startswith(folder + os.sep)
def _state_paths(values: list, work: str):
"""Each state path as an absolute path strictly under the home and outside REA's work folder, both as named
and with its links resolved, or the refusal of the first that is not. The capture resolves the links again
and retains what they lead to, so a link out of the home is refused here. Each passes on as named, so the
capture keeps what its spelling means, such as a hidden settings folder."""
home = os.path.normpath(os.path.expanduser("~"))
real_home, real_work = os.path.realpath(home), os.path.realpath(work)
spellings = {home, real_home}
paths = []
for value in values:
relative = value[2:] if value.startswith("~/") else value
path = os.path.normpath(os.path.join(home, relative))
if ".." in relative.split("/") or not any(path.startswith(spelling + os.sep) for spelling in spellings):
return None, f"The state path {value} is not under the computer's home, {home}."
# Every link on the way is followed, a dangling one too; a path that does not exist yet resolves
# through its nearest existing folder.
resolved = os.path.realpath(path)
if not resolved.startswith(real_home + os.sep):
return None, f"The state path {value} leads through a link to {resolved}, which is not under the computer's home, {home}."
if _within(path, work) or _within(resolved, real_work):
return None, f"The state path {value} is in REA's work folder {work}, which every capture leaves out."
paths.append(path)
return paths, None
def start(arguments: dict) -> int:
work, capture = os.path.abspath(arguments["work"]), os.path.abspath(arguments["capture"])
rea = shutil.which("rea")
if rea is None:
return _say({"error": "REA is not installed in this computer; start the computer from a request, which installs it."})
state_paths, refusal = _state_paths(arguments.get("state_paths", []), work)
if refusal is not None:
return _say({"refused": refusal})
if os.path.exists(capture):
return _say({"error": f"the capture folder {capture} is already used"})
apt = _apt(work, arguments.get("apt_timeout_s", 600))
@@ -143,20 +184,38 @@ def start(arguments: dict) -> int:
"--output", os.path.join(capture, "capture"), "--exclude", work, "--json"]
for value in arguments.get("arguments", []):
argv += ["--argument", value]
for path in state_paths:
argv += ["--state-path", path]
if arguments.get("package_file"):
argv += ["--package-file", arguments["package_file"]]
# Reading and writing, so the capture never reads the end of its input between requests.
reader = os.open(control, os.O_RDWR)
process = None
try:
with open(os.path.join(capture, "capture.out"), "wb") as out, \
open(os.path.join(capture, "progress.log"), "wb") as progress:
process = subprocess.Popen(
["sh", "-c", 'done=$1; shift; "$@"; code=$?; printf "%s" "$code" > "$done.tmp" && mv "$done.tmp" "$done"',
"sh", os.path.join(capture, "exit"), *argv],
cwd=os.path.expanduser("~"), env=_environment(work), stdin=reader, stdout=out, stderr=progress,
start_new_session=True)
try:
with open(os.path.join(capture, "capture.out"), "wb") as out, \
open(os.path.join(capture, "progress.log"), "wb") as progress:
process = subprocess.Popen(
["sh", "-c", 'done=$1; shift; "$@"; code=$?; printf "%s" "$code" > "$done.tmp" && mv "$done.tmp" "$done"',
"sh", os.path.join(capture, "exit"), *argv],
cwd=os.path.expanduser("~"), env=_environment(work), stdin=reader, stdout=out, stderr=progress,
start_new_session=True)
except Exception as cause:
# Nothing will write exit. Record one and drop the FIFO, so stop does not wait on it.
try:
with open(os.path.join(capture, "exit"), "w", encoding="utf-8") as handle:
handle.write("1")
except OSError:
pass
try:
os.unlink(control)
except OSError:
pass
return _say({"error": f"the capture did not start: {cause}"})
finally:
os.close(reader)
if process is None:
return _say({"error": "the capture did not start"})
waited = _wait(capture, 0, {"window_open"}, None, arguments.get("timeout_s", 120))
return _say({"pid": process.pid, "apt": apt, **waited})
@@ -175,11 +234,13 @@ def _request(capture: str, line: str) -> bool:
def mark(arguments: dict) -> int:
"""Request a checkpoint and answer with the capture's acknowledgement line as it wrote it: the checkpoint's
counts and up to ten of the files that changed, home-relative, with a count of the rest."""
capture, name = os.path.abspath(arguments["capture"]), arguments["name"]
code = _exit_code(capture)
log = os.path.join(capture, "progress.log")
if code is not None:
return _say({"exited": code, "progress": _tail(log)})
return _say(_ended(capture, code))
# A checkpoint already taken, whose answer was lost, is answered from the capture's own log.
taken = _event_line(log, 0, {"checkpoint"}, name)
if taken is not None:
@@ -229,6 +290,187 @@ def run(arguments: dict) -> int:
"stderr": done.stderr[-TAIL_BYTES:].decode("utf-8", "replace")})
# The controller is sent with python -c, so a detached supervisor needs its
# own source. It alone holds the child process handle and signals its group.
LONG_RUN = r'''
import json, os, signal, subprocess, sys, threading, time
job = sys.argv[1]
result = {}
child = None
drainer = None
stderr_tail, stderr_errors = bytearray(), []
def drain(stream):
try:
while chunk := stream.read1(65536):
stderr_tail.extend(chunk)
del stderr_tail[:-4096]
except OSError as error:
stderr_errors.append(str(error))
finally:
try:
stream.close()
except OSError as error:
stderr_errors.append(str(error))
def timed_out_marker():
try:
open(os.path.join(job, "timed_out"), "x").close()
except FileExistsError:
pass
try:
request = json.loads("".join(sys.argv[2:]))
if os.path.exists(os.path.join(job, "cancel")):
result = {"absent": True}
else:
with open(request["stdout"], "wb") as out:
child = subprocess.Popen(request["argv"], cwd=request["home"], stdin=subprocess.DEVNULL,
stdout=out, stderr=subprocess.PIPE, start_new_session=True)
drainer = threading.Thread(target=drain, args=(child.stderr,), daemon=True)
drainer.start()
deadline = time.monotonic() + request["timeout_s"]
interrupted = False
timed_out = False
while child.poll() is None:
timed_out = timed_out or time.monotonic() >= deadline
if not interrupted and (timed_out or os.path.exists(os.path.join(job, "cancel"))):
interrupted = True
if timed_out:
timed_out_marker()
try:
os.killpg(child.pid, signal.SIGINT)
except OSError:
pass
time.sleep(0.2)
# A descendant can still hold stderr after the leader exits. Do
# not publish completion until that stream has actually closed.
while drainer.is_alive():
drainer.join(0.2)
if time.monotonic() >= deadline:
timed_out = True
timed_out_marker()
result = {"exit_code": child.returncode, "stdout_bytes": os.path.getsize(request["stdout"]),
"timed_out": timed_out, "cancelled": interrupted and not timed_out,
"stderr": bytes(stderr_tail).decode("utf-8", "replace")}
if stderr_errors:
result["error"] = f"The REA command's stderr could not be read: {stderr_errors[0]}"
except Exception as error:
result["error"] = f"The REA command supervisor failed: {error}"
# Keep the child handle until it exits, including when cancellation arrives
# after an unexpected supervisor error.
while child is not None and child.poll() is None:
if os.path.exists(os.path.join(job, "cancel")):
try:
os.killpg(child.pid, signal.SIGINT)
except OSError:
pass
time.sleep(0.2)
if drainer is not None and drainer.ident is not None:
drainer.join()
if child is not None:
result.setdefault("exit_code", child.returncode)
result.setdefault("stderr", bytes(stderr_tail).decode("utf-8", "replace"))
try:
result.setdefault("stdout_bytes", os.path.getsize(request["stdout"]))
except OSError:
pass
if child is None or child.poll() is not None:
temporary = os.path.join(job, "result.tmp")
with open(temporary, "w", encoding="utf-8") as out:
json.dump(result, out)
os.replace(temporary, os.path.join(job, "result.json"))
'''
def run_begin(arguments: dict) -> int:
"""Start one long REA command in its own capture-owned job folder."""
rea = shutil.which("rea")
if rea is None:
return _say({"error": "REA is not installed in this computer"})
job = os.path.abspath(arguments["job"])
os.makedirs(os.path.dirname(job), exist_ok=True)
try:
os.mkdir(job, 0o700)
except FileExistsError:
return _say({"refused": "the command job folder is already used"})
process = None
try:
with open(os.path.join(job, "owner"), "x", encoding="ascii") as out:
out.write(arguments["token"])
for path, text in arguments.get("files", {}).items():
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "w", encoding="utf-8") as handle:
handle.write(text)
os.makedirs(os.path.dirname(arguments["stdout"]), exist_ok=True)
request = json.dumps({"argv": [rea, *arguments["argv"]], "stdout": arguments["stdout"],
"home": os.path.expanduser("~"), "timeout_s": arguments["timeout_s"]})
chunks = [request[i:i + 60000] for i in range(0, len(request), 60000)]
with open(os.path.join(job, "supervisor.log"), "wb") as log:
process = subprocess.Popen([sys.executable, "-I", "-c", LONG_RUN, job, *chunks], cwd=os.path.expanduser("~"),
env=_environment(os.path.abspath(arguments["work"])), stdin=subprocess.DEVNULL,
stdout=log, stderr=log, start_new_session=True)
except (OSError, ValueError) as error:
stage = "did not start" if process is None else "started but its setup did not finish"
result = {"error": f"The REA command supervisor {stage}: {error}"}
if process is None:
temporary = os.path.join(job, "result.tmp")
with open(temporary, "w", encoding="utf-8") as out:
json.dump(result, out)
os.replace(temporary, os.path.join(job, "result.json"))
return _say(result)
return _say({"started": True})
def _run_result(job: str):
try:
with open(os.path.join(job, "result.json"), encoding="utf-8") as source:
return json.load(source)
except FileNotFoundError:
return None
def _owns_run(job: str, token: str) -> bool:
try:
with open(os.path.join(job, "owner"), encoding="ascii") as owner:
return owner.read() == token
except OSError:
return False
def run_poll(arguments: dict) -> int:
job = os.path.abspath(arguments["job"])
if not _owns_run(job, arguments["token"]):
return _say({"error": "the command job ownership is not confirmed"})
deadline = time.monotonic() + arguments.get("timeout_s", 30)
while (result := _run_result(job)) is None and time.monotonic() < deadline:
time.sleep(POLL_S)
if result is None:
pending = {"pending": True, "timed_out": os.path.exists(os.path.join(job, "timed_out"))}
progress = _tail(os.path.join(job, "supervisor.log"))
return _say({**pending, **({"progress": progress} if progress else {})})
return _say({"finished": True, **result})
def run_cancel(arguments: dict) -> int:
job = os.path.abspath(arguments["job"])
os.makedirs(os.path.dirname(job), exist_ok=True)
try:
os.mkdir(job, 0o700)
except FileExistsError:
pass
else:
# A late begin cannot launch into a folder cancellation claimed.
with open(os.path.join(job, "owner"), "x", encoding="ascii") as owner:
owner.write(arguments["token"])
return _say({"absent": True})
if not _owns_run(job, arguments["token"]):
return _say({"error": "the command job ownership is not confirmed"})
with open(os.path.join(job, "cancel"), "a", encoding="utf-8"):
pass
return run_poll(arguments)
def listing(arguments: dict) -> int:
"""Every regular file under a folder, by its path relative to the home, with its size and SHA-256.
@@ -267,7 +509,8 @@ def listing(arguments: dict) -> int:
return _say({"listing_bytes": os.path.getsize(output)})
COMMANDS = {"start": start, "mark": mark, "stop": stop, "run": run, "list": listing}
COMMANDS = {"start": start, "mark": mark, "stop": stop, "run": run, "list": listing,
"run-begin": run_begin, "run-poll": run_poll, "run-cancel": run_cancel}
if __name__ == "__main__":
sys.exit(COMMANDS[sys.argv[1]](json.loads(sys.argv[2])))
sys.exit(COMMANDS[sys.argv[1]](json.loads("".join(sys.argv[2:]))))
+168
View File
@@ -1,12 +1,17 @@
"""Exercise the capture controller's filesystem inventory boundary."""
import json
import io
from contextlib import redirect_stdout
import os
from pathlib import Path
import subprocess
import sys
import tempfile
import unittest
from unittest.mock import patch
from bridge.agentenv import capture
CONTROLLER = Path(__file__).with_name("capture.py")
@@ -60,5 +65,168 @@ class CaptureListingTest(unittest.TestCase):
self.assertFalse(output.exists())
@unittest.skipIf(sys.platform == "win32", "desktop build computers use Linux")
class LongRunTest(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.addCleanup(self.tmp.cleanup)
self.root = Path(self.tmp.name)
self.bin = self.root / "bin"
self.bin.mkdir()
rea = self.bin / "rea"
rea.write_text(
f"#!{sys.executable}\n"
"import os, signal, subprocess, sys, time\n"
"signal.signal(signal.SIGINT, lambda *_: sys.exit(130))\n"
"if len(sys.argv) > 1 and sys.argv[1] == 'wait':\n"
" open(sys.argv[2], 'w').close()\n"
" time.sleep(30)\n"
"if len(sys.argv) > 1 and sys.argv[1] == 'ignore':\n"
" signal.signal(signal.SIGINT, signal.SIG_IGN)\n"
" open(sys.argv[2], 'w').close()\n"
" while not os.path.exists(sys.argv[3]): time.sleep(0.02)\n"
"if len(sys.argv) > 1 and sys.argv[1] == 'stderr':\n"
" sys.stderr.write('x' * 100000 + 'TAIL')\n"
"if len(sys.argv) > 1 and sys.argv[1] == 'hold':\n"
" subprocess.Popen([sys.executable, '-c', 'import os,sys,time\\nwhile not os.path.exists(sys.argv[1]): time.sleep(0.02)', sys.argv[2]], stdout=subprocess.DEVNULL, stderr=sys.stderr, start_new_session=True)\n"
" sys.exit(0)\n"
"print(os.environ.get('AGENTENV_CONTROL_TOKEN', 'no token'))\n"
)
rea.chmod(0o755)
self.environment = {**os.environ, "HOME": str(self.root), "PATH": f"{self.bin}{os.pathsep}{os.environ.get('PATH', '')}",
"AGENTENV_CONTROL_TOKEN": "not-for-the-child"}
self.job = self.root / "job"
self.output = self.root / "out.json"
def command(self, name, **values):
result = subprocess.run([sys.executable, str(CONTROLLER), name, json.dumps(values)],
env=self.environment, text=True, capture_output=True, timeout=10, check=True)
return json.loads(result.stdout)
def begin(self, argv, timeout=60):
return self.command("run-begin", job=str(self.job), work=str(self.root), stdout=str(self.output),
token="owner-token", argv=argv, files={}, timeout_s=timeout)
def test_runs_and_reports_its_output(self):
self.assertEqual(self.begin([]), {"started": True})
result = self.command("run-poll", job=str(self.job), token="owner-token", timeout_s=5)
self.assertEqual(result["exit_code"], 0)
self.assertEqual(self.output.read_text().strip(), "no token")
def test_passes_large_command_without_persisting_its_arguments(self):
self.assertEqual(self.begin(["done", *("x" * 4000 for _ in range(20))]), {"started": True})
result = self.command("run-poll", job=str(self.job), token="owner-token", timeout_s=5)
self.assertEqual(result["exit_code"], 0)
self.assertFalse((self.job / "request.json").exists())
def test_keeps_only_a_bounded_stderr_tail(self):
self.assertEqual(self.begin(["stderr"]), {"started": True})
result = self.command("run-poll", job=str(self.job), token="owner-token", timeout_s=5)
self.assertEqual(len(result["stderr"]), 4096)
self.assertTrue(result["stderr"].endswith("TAIL"))
def test_cancels_a_running_child_and_confirms_exit(self):
ready = self.root / "ready"
self.assertEqual(self.begin(["wait", str(ready)]), {"started": True})
import time
deadline = time.monotonic() + 5
while not ready.exists() and time.monotonic() < deadline:
time.sleep(0.02)
self.assertTrue(ready.exists())
result = self.command("run-cancel", job=str(self.job), token="owner-token", timeout_s=5)
self.assertTrue(result["cancelled"])
self.assertEqual(result["exit_code"], 130)
def test_cancel_before_late_start_claims_the_job(self):
self.assertEqual(self.command("run-cancel", job=str(self.job), token="owner-token", timeout_s=1), {"absent": True})
self.assertIn("already used", self.begin([])["refused"])
self.assertFalse(self.output.exists())
def test_cancel_refuses_a_folder_without_the_matching_owner(self):
self.job.mkdir()
(self.job / "owner").write_text("someone-else")
result = self.command("run-cancel", job=str(self.job), token="owner-token", timeout_s=1)
self.assertIn("ownership is not confirmed", result["error"])
self.assertFalse((self.job / "cancel").exists())
def test_reports_supervisor_output_if_completion_is_unconfirmed(self):
self.job.mkdir()
(self.job / "owner").write_text("owner-token")
(self.job / "supervisor.log").write_text("supervisor failed")
result = self.command("run-poll", job=str(self.job), token="owner-token", timeout_s=0)
self.assertEqual(result["progress"], "supervisor failed")
self.assertTrue(result["pending"])
def test_reports_a_timed_out_child_that_has_not_stopped(self):
ready, release = self.root / "ready", self.root / "release"
self.assertEqual(self.begin(["ignore", str(ready), str(release)], timeout=3), {"started": True})
try:
result = self.command("run-poll", job=str(self.job), token="owner-token", timeout_s=4)
self.assertTrue(result["pending"])
self.assertTrue(result["timed_out"])
self.assertTrue(ready.exists())
finally:
release.touch()
self.command("run-poll", job=str(self.job), token="owner-token", timeout_s=5)
def test_waits_for_an_inherited_stderr_pipe_after_the_child_exits(self):
release = self.root / "release"
self.assertEqual(self.begin(["hold", str(release)], timeout=3), {"started": True})
try:
result = self.command("run-poll", job=str(self.job), token="owner-token", timeout_s=4)
self.assertTrue(result["pending"])
self.assertTrue(result["timed_out"])
finally:
release.touch()
result = self.command("run-poll", job=str(self.job), token="owner-token", timeout_s=5)
self.assertTrue(result["finished"])
def test_failure_closing_supervisor_log_after_launch_does_not_claim_exit(self):
ready = self.root / "ready"
original_open = open
original_popen = subprocess.Popen
supervisors = []
class FailingClose:
def __init__(self, file):
self.file = file
def __enter__(self):
return self.file
def __exit__(self, *args):
self.file.close()
raise OSError("log close failed")
def opening(path, *args, **kwargs):
file = original_open(path, *args, **kwargs)
return FailingClose(file) if str(path).endswith("supervisor.log") else file
def spawning(*args, **kwargs):
process = original_popen(*args, **kwargs)
supervisors.append(process)
def cleanup():
if process.poll() is None:
(self.job / "cancel").touch()
process.wait(timeout=5)
self.addCleanup(cleanup)
return process
arguments = {"job": str(self.job), "work": str(self.root), "stdout": str(self.output),
"token": "owner-token", "argv": ["wait", str(ready)], "files": {}, "timeout_s": 60}
with patch.dict(os.environ, self.environment, clear=True), patch("builtins.open", side_effect=opening), patch.object(capture.subprocess, "Popen", side_effect=spawning), redirect_stdout(io.StringIO()) as output:
capture.run_begin(arguments)
self.assertIn("started but its setup did not finish", json.loads(output.getvalue())["error"])
import time
deadline = time.monotonic() + 5
while not ready.exists() and time.monotonic() < deadline:
time.sleep(0.02)
self.assertTrue(ready.exists())
self.assertFalse((self.job / "result.json").exists())
result = self.command("run-cancel", job=str(self.job), token="owner-token", timeout_s=5)
self.assertTrue(result["cancelled"])
supervisors[0].wait(timeout=5)
if __name__ == "__main__":
unittest.main()
+42 -4
View File
@@ -3753,6 +3753,20 @@ public final class ReaGhidraBridge extends HeadlessScript {
private JsonObject callRelationshipCoverage(
CallBoundaryObservation calls, Integer missingCallers) {
JsonObject coverage = completeResolvedCallCoverage();
JsonObject discovery = new JsonObject();
if (missingCallers != null) {
JsonObject callers = new JsonObject();
callers.addProperty("status", "unknown");
callers.addProperty("reason", "Recorded incoming references do not establish additional computed callers elsewhere in the program.");
discovery.add("callers", callers);
}
if (calls != null && !calls.computedCallSites().isEmpty()) {
JsonObject callees = new JsonObject();
callees.addProperty("status", "unknown");
callees.addProperty("reason", computedCallTargetLimitation(calls.computedCallSites()));
discovery.add("callees", callees);
}
if (!discovery.isEmpty()) coverage.add("discovery", discovery);
Integer omitted = calls == null ? null : calls.unrepresentedCalleeCalls();
JsonArray directions = new JsonArray();
if (missingCallers != null && missingCallers > 0) directions.add("callers");
@@ -3771,10 +3785,10 @@ public final class ReaGhidraBridge extends HeadlessScript {
}
JsonArray limitations = new JsonArray();
if (callerLimitation != null) limitations.add(callerLimitation);
if (omitted != null && omitted > 0) directions.add("callees");
if (omitted != null && omitted > 0) {
limitations.add("Ghidra's callee inventory omits targets of " + omitted +
" call reference(s) or decoded call(s) without destinations.");
directions.add("callees");
}
if (!limitations.isEmpty()) {
coverage.addProperty("status", "partial");
@@ -3824,6 +3838,24 @@ public final class ReaGhidraBridge extends HeadlessScript {
return coverage;
}
/** Name a few sites inline; reference reads and call-target queries recover the rest. */
private static final int NAMED_COMPUTED_CALL_SITES = 4;
/**
* A computed call's ReferenceManager targets are static candidates: Ghidra
* records no proof that other values cannot reach the call, so the callee
* set stays incomplete while the recorded candidates remain observed.
*/
private static String computedCallTargetLimitation(List<String> sites) {
if (sites.isEmpty()) return null;
int named = Math.min(sites.size(), NAMED_COMPUTED_CALL_SITES);
String listed = String.join(", ", sites.subList(0, named)) +
(sites.size() > named ? " and " + (sites.size() - named) + " more" : "");
return "Ghidra records call reference targets at " + sites.size() +
" computed call site(s) (" + listed + "); these static references do not establish" +
" every possible target, so additional callees remain unknown.";
}
private boolean unrepresentedCaller(Reference reference, Set<Function> callers) {
if (!reference.getReferenceType().isCall()) return false;
Function caller = functionAtOrContaining(reference.getFromAddress());
@@ -3858,9 +3890,11 @@ public final class ReaGhidraBridge extends HeadlessScript {
monitor.checkCancelled();
calls.observe(reference);
}
List<String> computedCallSites = new ArrayList<>();
for (Instruction instruction : instructions) {
boundary.observe(instruction);
if (!instruction.getFlowType().isCall()) continue;
FlowType flow = instruction.getFlowType();
if (!flow.isCall()) continue;
boolean destination = false;
for (Reference reference : instruction.getReferencesFrom()) {
if (!reference.getReferenceType().isCall()) continue;
@@ -3872,9 +3906,13 @@ public final class ReaGhidraBridge extends HeadlessScript {
calls.unresolved(instruction.getAddress(),
"Instruction decoder identifies a call but ReferenceManager supplies no call destination");
}
// The same decoded flow classifies resolve_native_call_targets'
// mechanism; its recorded targets are candidates, not a closed set.
else if (flow.isComputed()) computedCallSites.add(canonicalAddress(instruction.getAddress()));
}
return new CallBoundaryObservation(boundary.values(),
returnedCallees == null ? null : calls.unrepresented, calls.unresolvedCalls());
returnedCallees == null ? null : calls.unrepresented, calls.unresolvedCalls(),
List.copyOf(computedCallSites));
}
private final class FunctionBoundaryLimitations {
@@ -5320,7 +5358,7 @@ public final class ReaGhidraBridge extends HeadlessScript {
}
}
private record FunctionAnalysisObservation(JsonObject dossier, List<String> limitations, JsonObject relationshipCoverage, boolean decompilerFailed) {}
private record CallBoundaryObservation(List<String> limitations, Integer unrepresentedCalleeCalls, JsonArray unresolvedCalls) {}
private record CallBoundaryObservation(List<String> limitations, Integer unrepresentedCalleeCalls, JsonArray unresolvedCalls, List<String> computedCallSites) {}
private record SwiftStringLiteralDecode(JsonArray literals, JsonArray omissions) {}
private record SwiftLiteralLayout(
String representation,
+2 -1
View File
@@ -1399,7 +1399,8 @@ def _serve_connection(connection):
break
except (ConnectionError, OSError):
# A lost client cannot confirm document closure or revoke this run.
pass
# Keep the listener available for the owner to confirm cleanup.
should_stop = False
finally:
try:
file.close()
+13
View File
@@ -24,3 +24,16 @@ func captureAccessibilityValue(_ source: Any?) -> AccessibilityValue {
}
return AccessibilityValue(value: NSNull(), gap: "AXValue type \(type(of: source)) is not a supported JSON scalar")
}
/** Keep an unavailable action list distinct from a successful empty list. */
func captureActionNames(status: Int32, success: Int32, names: [String]?) -> (names: [String], error: Int32?) {
guard status == success else { return ([], status) }
return (names ?? [], nil)
}
/** AX absence is distinct from a failed attribute read. */
func captureAttributeValue<Value>(status: Int32, success: Int32, absent: [Int32], value: Value?) -> (value: Value?, error: Int32?) {
if status == success { return (value, nil) }
if absent.contains(status) { return (nil, nil) }
return (nil, status)
}
+45 -20
View File
@@ -18,9 +18,10 @@ struct Request: Decodable {
struct Action: Decodable { var kind: String; var path: [Int]?; var direction: String?; var text: String? }
struct BoundaryFailure: Error { var code: String; var message: String }
func fail(_ code: String, _ message: String) throws -> Never { throw BoundaryFailure(code: code, message: message) }
func attribute(_ element: AXUIElement, _ key: String) -> CFTypeRef? {
func attribute(_ element: AXUIElement, _ key: String) -> (value: CFTypeRef?, error: Int32?) {
var value: CFTypeRef?
return AXUIElementCopyAttributeValue(element, key as CFString, &value) == .success ? value : nil
let status = AXUIElementCopyAttributeValue(element, key as CFString, &value)
return captureAttributeValue(status: status.rawValue, success: AXError.success.rawValue, absent: [AXError.noValue.rawValue, AXError.attributeUnsupported.rawValue], value: value)
}
func childCount(_ element: AXUIElement) -> ChildCount {
var count = 0
@@ -34,13 +35,15 @@ func children(_ element: AXUIElement, count: Int) -> ChildBatch<AXUIElement> {
return value as? [AXUIElement]
}
}
func text(_ element: AXUIElement, _ key: String) -> Any { (attribute(element, key) as? String) ?? NSNull() as Any }
func windowBounds(_ element: AXUIElement) -> CGRect? {
guard let p = attribute(element, kAXPositionAttribute), let s = attribute(element, kAXSizeAttribute),
CFGetTypeID(p) == AXValueGetTypeID(), CFGetTypeID(s) == AXValueGetTypeID() else { return nil }
var point = CGPoint.zero; var size = CGSize.zero
guard AXValueGetValue(p as! AXValue, .cgPoint, &point), AXValueGetValue(s as! AXValue, .cgSize, &size) else { return nil }
return CGRect(origin: point, size: size)
func windowBounds(_ element: AXUIElement) -> (bounds: CGRect?, error: Int32?) {
let position = attribute(element, kAXPositionAttribute)
let size = attribute(element, kAXSizeAttribute)
if let error = position.error ?? size.error { return (nil, error) }
guard let p = position.value, let s = size.value,
CFGetTypeID(p) == AXValueGetTypeID(), CFGetTypeID(s) == AXValueGetTypeID() else { return (nil, nil) }
var point = CGPoint.zero; var dimensions = CGSize.zero
guard AXValueGetValue(p as! AXValue, .cgPoint, &point), AXValueGetValue(s as! AXValue, .cgSize, &dimensions) else { return (nil, nil) }
return (CGRect(origin: point, size: dimensions), nil)
}
func observe(_ request: Request) async throws -> [String: Any] {
guard let app = NSRunningApplication(processIdentifier: request.pid) else {
@@ -84,11 +87,22 @@ func observe(_ request: Request) async throws -> [String: Any] {
guard AXIsProcessTrusted() else { try fail("accessibility-denied", "Grant Accessibility to the REA host in System Settings > Privacy & Security, then retry") }
let application = AXUIElementCreateApplication(request.pid)
AXUIElementSetMessagingTimeout(application, 2)
guard let axWindows = attribute(application, kAXWindowsAttribute) as? [AXUIElement] else {
try fail("accessibility-unavailable", "Selected application does not expose accessibility windows")
let windowsAttribute = attribute(application, kAXWindowsAttribute)
if let error = windowsAttribute.error {
try fail("accessibility-unavailable", "Cannot read accessibility windows: AXError \(error)")
}
let matches = axWindows.filter { windowBounds($0) == bounds }
guard matches.count == 1 else { try fail("ambiguous-window", "Accessibility window geometry does not identify exactly one selected window; selected CG bounds \(bounds), AX candidates \(axWindows.map { String(describing: windowBounds($0)) })") }
guard let axWindows = windowsAttribute.value as? [AXUIElement] else {
try fail("accessibility-unavailable", "Accessibility windows are unavailable for the selected application")
}
let candidates = axWindows.map { (element: $0, observation: windowBounds($0)) }
if let error = candidates.compactMap({ $0.observation.error }).first {
try fail("accessibility-unavailable", "Cannot read accessibility window geometry: AXError \(error)")
}
guard candidates.allSatisfy({ $0.observation.bounds != nil }) else {
try fail("accessibility-unavailable", "Accessibility window geometry is unavailable; the selected window cannot be identified")
}
let matches = candidates.filter { $0.observation.bounds == bounds }.map { $0.element }
guard matches.count == 1 else { try fail("ambiguous-window", "Accessibility window geometry does not identify exactly one selected window; selected CG bounds \(bounds), AX candidates \(candidates.map { String(describing: $0.observation.bounds) })") }
selected = matches[0]
}
if let action = request.action, let root = selected {
@@ -99,13 +113,16 @@ func observe(_ request: Request) async throws -> [String: Any] {
guard let available = count.value else {
try fail("element-count-unavailable", "Cannot validate selected accessibility path because child count failed with AXError \(count.error ?? -1)")
}
guard index >= 0 && index < available,
AXUIElementCopyAttributeValues(element, kAXChildrenAttribute as CFString, index, 1, &selectedChild) == .success,
let item = (selectedChild as? [AXUIElement])?.first else { try fail("element-missing", "Selected accessibility path no longer exists") }
guard index >= 0 && index < available else { try fail("element-missing", "Selected accessibility path no longer exists") }
let childStatus = AXUIElementCopyAttributeValues(element, kAXChildrenAttribute as CFString, index, 1, &selectedChild)
guard childStatus == .success else { try fail("accessibility-unavailable", "Cannot read selected accessibility child: AXError \(childStatus.rawValue)") }
guard let item = (selectedChild as? [AXUIElement])?.first else { try fail("accessibility-unavailable", "Selected accessibility child was not returned") }
element = item
}
var owner: pid_t = 0
guard AXUIElementGetPid(element, &owner) == .success && owner == request.pid else { try fail("element-owner-mismatch", "Selected element belongs to another process") }
let ownerStatus = AXUIElementGetPid(element, &owner)
guard ownerStatus == .success else { try fail("accessibility-unavailable", "Cannot identify accessibility element owner: AXError \(ownerStatus.rawValue)") }
guard owner == request.pid else { try fail("element-owner-mismatch", "Selected element belongs to another process") }
let outcome: AXError
switch action.kind {
case "click": outcome = AXUIElementPerformAction(element, kAXPressAction as CFString)
@@ -122,10 +139,18 @@ func observe(_ request: Request) async throws -> [String: Any] {
if nodes.count >= request.max_nodes { truncated = true; break }
let childCountResult = childCount(element)
var actions: CFArray?
AXUIElementCopyActionNames(element, &actions)
let observedValue = captureAccessibilityValue(attribute(element, kAXValueAttribute))
let actionStatus = AXUIElementCopyActionNames(element, &actions)
let observedActions = captureActionNames(status: actionStatus.rawValue, success: AXError.success.rawValue, names: actions as? [String])
if let error = observedActions.error { gaps.append("AX actions unavailable at path \(path): AXError \(error)"); truncated = true }
let role = attribute(element, kAXRoleAttribute)
let title = attribute(element, kAXTitleAttribute)
let value = attribute(element, kAXValueAttribute)
for (name, error) in [("role", role.error), ("title", title.error), ("value", value.error)] {
if let error { gaps.append("AX \(name) unavailable at path \(path): AXError \(error)"); truncated = true }
}
let observedValue = captureAccessibilityValue(value.value)
if let gap = observedValue.gap { gaps.append("\(gap) at path \(path)"); truncated = true }
nodes.append(["path": path, "role": text(element, kAXRoleAttribute), "title": text(element, kAXTitleAttribute), "value": observedValue.value, "actions": actions as? [String] ?? [], "children_count": childCountResult.value.map { $0 as Any } ?? NSNull()])
nodes.append(["path": path, "role": (role.value as? String) ?? NSNull() as Any, "title": (title.value as? String) ?? NSNull() as Any, "value": observedValue.value, "actions": observedActions.names, "children_count": childCountResult.value.map { $0 as Any } ?? NSNull()])
guard let totalChildren = childCountResult.value else {
truncated = true
gaps.append("AX child count unavailable at path \(path): AXError \(childCountResult.error ?? -1)")
+7 -5
View File
@@ -78,14 +78,9 @@ public final class NativeAotExtension {
new FrozenObjectAnnotator(program, manager).analyze(located.directory(), scan.getPointerLocations(), monitor, log);
}
monitor.checkCancelled();
report.addProperty("method_tables", manager.getMethodTableCount());
JsonObject coverage = auditFrozenObjects(program, scan.getPointerLocations(), monitor);
report.add("coverage", coverage);
if (coverage.get("frozen_objects_annotated").getAsInt() != coverage.get("frozen_object_candidates").getAsInt())
diagnostics.add("Some frozen-object candidates lack committed instance annotations; inspect coverage counts and Ghidra diagnostics.");
report.addProperty("status", diagnostics.isEmpty() ? "complete" : "partial");
report.add("reason", JsonNull.INSTANCE);
report.add("derived_memory", derivedRange.deepCopy());
JsonArray tables = new JsonArray();
for (var mt : manager.getMethodTables()) {
monitor.checkCancelled();
@@ -94,6 +89,13 @@ public final class NativeAotExtension {
identity.addProperty("type", mt.getMTType().getPathName());
tables.add(identity);
}
// Publish recovery facts only after every fallible recovery and audit step.
// A failed transaction is rolled back, so it cannot report committed metadata.
report.addProperty("method_tables", manager.getMethodTableCount());
report.add("coverage", coverage);
report.addProperty("status", diagnostics.isEmpty() ? "complete" : "partial");
report.add("reason", JsonNull.INSTANCE);
report.add("derived_memory", derivedRange.deepCopy());
report.add("types", tables);
commit = true;
return finish(log);
+30
View File
@@ -43,11 +43,31 @@ export const documentationSections = [
source: "guides/native/binary-diagnostics.md",
route: "/binary-diagnostics",
},
{
text: "ELF and Mach-O initializer functions",
source: "guides/native/native-initializers.md",
route: "/native-initializers",
},
{
text: "ELF unwind function ranges",
source: "guides/native/elf-unwind-ranges.md",
route: "/elf-unwind-ranges",
},
{
text: "Linux kernel build config",
source: "guides/native/kernel-build-config.md",
route: "/kernel-build-config",
},
{
text: "Recorded crash evidence",
source: "guides/native/recorded-crashes.md",
route: "/recorded-crashes",
},
{
text: "Windows Shell Link shortcuts",
source: "guides/native/windows-shortcut.md",
route: "/windows-shortcut",
},
],
},
{
@@ -88,6 +108,11 @@ export const documentationSections = [
source: "guides/javascript/electron-observation.md",
route: "/electron-observation",
},
{
text: "V8 code cache inspection",
source: "guides/javascript/v8-code-cache.md",
route: "/v8-code-cache",
},
],
},
{
@@ -398,6 +423,11 @@ export const documentationSections = [
source: "bun-standalone.md",
route: "/bun-standalone",
},
{
text: "Deno compile executables",
source: "deno-standalone.md",
route: "/deno-standalone",
},
{
text: "Capability composition and ownership",
source: "capability-composition.md",
+6
View File
@@ -16,7 +16,11 @@ product pages. The VitePress documentation source is this `docs/` tree.
- [Native binary investigation](guides/native/native-investigation.md)
- [Go binary build metadata](guides/native/go-binaries.md)
- [Offline binary diagnostics](guides/native/binary-diagnostics.md)
- [ELF and Mach-O initializer functions](guides/native/native-initializers.md)
- [ELF unwind function ranges](guides/native/elf-unwind-ranges.md)
- [Linux kernel build config](guides/native/kernel-build-config.md)
- [Recorded crash evidence](guides/native/recorded-crashes.md)
- [Windows Shell Link shortcuts](guides/native/windows-shortcut.md)
## JavaScript and Electron
@@ -27,6 +31,7 @@ product pages. The VitePress documentation source is this `docs/` tree.
- [Passive Node and Electron runtime observation](guides/javascript/javascript-runtime-observation.md)
- [JavaScript static/runtime reconciliation](guides/javascript/javascript-runtime-reconciliation.md)
- [Electron file-page observation](guides/javascript/electron-observation.md)
- [V8 code cache inspection](guides/javascript/v8-code-cache.md)
## Browser and captured websites
@@ -143,6 +148,7 @@ the exact commit messages and references from the release they describe.
- [Offline API contract inventory](api-contracts.md)
- [Bun standalone executables](bun-standalone.md)
- [Deno compile executables](deno-standalone.md)
- [Capability composition and ownership](capability-composition.md)
- [.NET single-file bundles](dotnet-bundles.md)
- [ESP flash images](esp-flash-image.md)
+12 -6
View File
@@ -107,7 +107,10 @@ refusal names its stage: `environment-build` for the build's own checks,
`inspect_web_network_capture` and `inspect_analysis_view` for inspection and
projection, `environment-export` for the bundle. SIGINT cancels the build
(`cancelled`); before the bundle stage nothing is written, and a cancellation
during the write names the bundle it wrote. Stage progress is logged to stderr
after publication preserves the bundle receipt. Before publication, a failed
write attempts to remove partial output and reports cleanup failures. See
[bundle publication and recovery](getting-started/cli.md#export-an-environment-bundle).
Stage progress is logged to stderr
at info level; the report is the only output on stdout:
```json
@@ -209,9 +212,9 @@ warning does not establish that these bodies were checked. A browser scenario's
saved values (`save` and `save_response`) named like credentials but not marked
`secret: true` are recorded unredacted; `credential-named-saved-values` lists up
to 20 of them by parameter pointer. Names do not establish sensitivity,
so the build never refuses on them. Capture
so the build never refuses on them.
Evidence also records the capture file's absolute path (`subject.local_path`,
Capture Evidence also records the capture file's absolute path (`subject.local_path`,
`parameters.capture_path`, `locations`, `artifact.path`), and the bundle
carries it: build from a neutral folder when that path should not ship.
@@ -332,9 +335,12 @@ scenario is written and cannot use a value an earlier response returned, so an
id must be known before the run: one the caller chooses, such as a `uid` in the
create body, or one an earlier scenario created. When the server assigns ids,
read the list after each create (the create's response or the list shows the
new entity), and record updates and deletes in a second scenario that reads
the first one's objects by id before editing them, or make them through the
UI. The environment coverage view names each
new entity). A second scenario can record updates and deletes using those
known ids, but produces a separate environment: recordings are not combined.
That scenario must include its own before/after reads and every action the
environment should support; it does not inherit the first scenario's create
evidence. To capture create and subsequent edits together, make them through
the UI in one scenario. The environment coverage view names each
write it withholds and what to record next. A scenario with write requests
changes the application's data: record against an instance whose data may
change.
+67 -4
View File
@@ -85,9 +85,49 @@ canonical hexadecimal form), `EXC_GUARD` subtypes,
pointer-authentication suffixes, and dyld missing-library strings. A report
that matches none of those rules is `unclassified`.
Opened Mach-O and dSYM UUID joins remain unobserved. Symbol names printed
inside the report are recorded claims and are not verified. Linux ELF cores
use the separate [recorded crash](guides/native/recorded-crashes.md) workflow.
## Joining frames to the crashed Mach-O or dSYM
Pass `join_path` (`--join-path` in the CLI) to select one local Mach-O
executable or dSYM. UUID bytes in the report and the artifact's `LC_UUID` load
commands are compared in hexadecimal, so an uppercase `dwarfdump --uuid` value
and a lowercase report `uuid` match.
```bash
rea inspect-apple-ips /absolute/path/to/report.ips \
--join-path /absolute/path/to/App.app/Contents/MacOS/App --json
```
Shared-cache image sources `S` and `C` remain unjoined: UUID agreement does not
establish that a standalone image has the cached layout.
For a FAT container every slice is examined. An image joins only when exactly
one slice has that UUID **and** an architecture that agrees with the report's
`arch`; `arm64` and `arm64e` stay distinct, and an all-zero UUID never joins. A
UUID match with a different architecture, more than one compatible slice, or a
slice without a readable `__TEXT` segment is reported as a rejected image with
its reason and stays unjoined rather than being guessed.
An unknown UUID in another slice prevents a unique join unless its architecture
rules out a match. Missing or unrecognized architecture and unsupported CPU
subtypes remain unknown; display-name fallbacks do not establish agreement.
The parsed slice facts remain available even when no match can be derived.
`join.status` is `selected` with the artifact path, SHA-256, byte length, every
slice's offset, arch, CPU type and subtype, UUID, and `__TEXT` vmaddr, plus
`image_matches`, per-frame results, and join-specific limitations. A joined
frame reports `static_address`, the slice `__TEXT` vmaddr plus the frame's
recorded `imageOffset`, in decimal and hexadecimal. An unjoined frame reports
a reason instead; an unknown image UUID, an absent `imageIndex` row, and a
frame without `imageOffset` all stay unjoined rather than treated as aligned.
An artifact that is not a Mach-O image or FAT container reports
`join.status: "unreadable"` with a typed reason and leaves every report fact
intact. Symbol names printed inside the report stay recorded claims. Function
or symbol lookup at a joined static address, and matching dSYM symbol tables,
are not performed by this step.
Symbol names printed inside the report are recorded claims and are not
verified. Linux ELF cores use the separate
[recorded crash](guides/native/recorded-crashes.md) workflow.
## Limits and failures
@@ -120,4 +160,27 @@ success or truncated integer facts.
rea inspect-apple-ips /absolute/path/to/report.ips --max-integer-text-bytes 16777216 --json
```
This workflow does not execute a target, launch atos, or search for dSYMs.
`max_join_bytes` (`--max-join-bytes`) independently bounds the join artifact
read, defaulting to 64 MiB. This workflow does not execute a target, launch
atos, or search for dSYMs.
## Join admission and failures
The join uses the shared Mach-O container, slice, command-table and segment
readers. Slice extents and `sizeofcmds` bound every identity observation; duplicate
UUIDs or malformed commands cannot select the first plausible value. Unreadable
join results retain the successfully read artifact's path, SHA-256 and byte count.
The integer-text allowance spans the report and join, including repeated integer
facts and derived static addresses. Reservation precedes derived address
expansion. If a selected join read, interpretation or allowance fails, the error
retains the completed IPS report. Join read limits and recovery use
`max_join_bytes`, even when the report and join paths are identical. Cancellation
retains the caller's reason independently of those completed facts.
When a failure follows a completed join-file read, `partial_observation` retains
both the decoded report and a `join_artifact` receipt with the independently
observed path, SHA-256 and byte count. Frame rejection reasons reference
`join.limitations`; source-sized architecture diagnostics are retained once per
image rather than copied into every frame. Universal-image admission includes
the shared reader's supported hidden ARM64 row and rejects overlapping slices.
+26
View File
@@ -0,0 +1,26 @@
# Deno compile executables
`inspect-artifact` inventories a `deno compile` executable. `extract-artifact` writes the embedded virtual files through the existing safe output tree. Neither operation runs the executable or the Deno runtime.
```sh
rea inspect-artifact ./app --json
rea extract-artifact ./app --json
```
In MCP, open the executable with `open_binary`, then call `inspect_artifact`. Use `detail: "summary"` for a large virtual filesystem and `inspect_analysis_view` to page retained Evidence.
The recognized carriers are a Mach-O `__SUI` section named `d3n0l4nd`, an Intel Mach-O `<~sui-data~>` trailer, an ELF `PT_NOTE` or `SHT_NOTE` owned by `SUI` with type `0x53554901` and descriptor name `d3n0l4nd`, and a PE `RT_RCDATA` resource named `D3N0L4ND`. These are structural layouts. The metadata JSON has no Deno version field, so the compiler version stays unknown unless another record establishes it. Other layouts, including older eszip trailers, are unsupported.
Root metadata reports the carrier, entry point, argv, V8 flags, permission options, unstable configuration, application name, self-extracting marker, virtual-filesystem case sensitivity, and the npm snapshot byte length. The npm snapshot is not decoded. Each virtual file is one occurrence with its logical path, size, and SHA-256. Transpiled output, CJS export analysis, and source maps are separate occurrences beside that file. Each has the same `index` as the file and its own `role`. A region normally has the logical path of the file plus a `.deno-*` suffix. When that path belongs to another stored file, the region moves to an indexed path such as `deno-vfs/0.vfs-transpiled`, so read the reported `logical_path` instead of building it from the file name. They are not linked by `parent_occurrence_id`, which follows directories and expanded containers. Symlink targets stay recorded path parts and are never followed.
`Metadata.env_vars_from_env_file` holds values from a compile-time `--env-file`, and `ca_data` holds certificate bytes. Inventory retains the variable names and values, certificate bytes, counts, and byte lengths in local Evidence, so sharing that Evidence shares them. Extraction does not write them as files.
A virtual filesystem that cannot be listed reports `vfs_listing` as `unsupported` and leaves inventory and extraction coverage unknown, because its files are not examined.
Remote modules, redirects, and specifiers contribute counts and logical paths when their stored form is unambiguous. When it is not, they stay present with a byte length and an `unsupported` member listing. A module whose specifier is missing uses an indexed `deno-remote/<index>` path, which still exposes its stored bytes, and modules with resolved specifiers keep their paths. Colons, backslashes, and control characters in a specifier are percent-encoded in the logical path, so `http://localhost:8000/mod.ts` becomes `deno-remote/localhost%3A8000/mod.ts`. Percent escapes in a logical path use uppercase hex, and a specifier that reaches a path already taken uses an indexed path. `source_path` keeps the original specifier. A remote specifier is indexed the same way when a path component exceeds 255 UTF-8 bytes or the logical path exceeds 512 UTF-8 bytes, counting the `.deno-*` suffix of its stored regions. Unsafe, deep, or over-long virtual names use `deno-vfs/<index>` under the same rule and retain the original spelling when it fits the name allowance. A descendant does not present its own name as a complete source path when an ancestor spelling was dropped.
A length that overruns the section, or a closing marker that does not match, is malformed. An opening marker that is absent is unsupported. A confirmed section that cannot be parsed fails closed and does not fall through to a plain native inventory. An Intel Mach-O sentinel inside a confirmed trailer payload is data of that payload, so an Intel Deno executable stored as a virtual file does not replace the app that stores it. Trailers side by side with different bytes fail closed. A file is confirmed only by its carrier name, so an unrelated native file with malformed tables keeps its native inventory. That inventory does not establish that the file holds no Deno section.
See [limits and recovery](design/limits-and-recovery.md) for the named allowances. Synthetic tests cover the carriers and malformed declarations. Run `npm run verify:deno:standalone` for a local Deno compile of the host and, when the compiler can produce them, Linux, Windows, and Intel macOS targets. Deno is a fixture producer only and is not installed by REA. The produced executable is not run.
Layout reference: Deno `cli/lib/standalone/binary.rs` and `cli/lib/standalone/virtual_fs.rs` at 2.9.8, with libsui 0.16.4 section placement.
+55
View File
@@ -430,3 +430,58 @@ artifact expansion budget also bounds the sum of referenced member lengths. Refu
There is no runtime override; additional host memory or `NODE_OPTIONS` does not
raise these ceilings. Use a smaller producer fixture or a separately reviewed
reader for larger graphs. No partial extraction is claimed on admission failure.
## Deno compile sections
`MAX_DENO_METADATA_JSON_BYTES` admits at most 8 MiB of metadata JSON.
`MAX_DENO_VFS_HEADER_JSON_BYTES` admits at most 32 MiB of virtual-filesystem
header JSON. Specifier, redirect, and remote tables each admit at most 100,000
records. Specifier text admits at most 8 MiB, and remote module bodies admit at
most 256 MiB. The virtual filesystem admits at most 100,000 directory, file,
and symlink records and at most 512 nested levels (`MAX_DENO_VFS_DEPTH`). A
name longer than 4,096 UTF-16 code units is indexed and is not retained.
`MAX_DENO_VFS_RETAINED_UNITS` admits at most 32 million UTF-16 code units across
the source path built for every entry, directories included, and retained
symlink parts. A logical path deeper than 256 parts, a name that is not a safe
relative path, a path component longer than 255 UTF-8 bytes
(`MAX_DENO_PATH_COMPONENT_BYTES`, POSIX `NAME_MAX`), or a logical path longer
than 512 UTF-8 bytes (`MAX_DENO_LOGICAL_PATH_BYTES`, half of the Darwin
`PATH_MAX`) uses an indexed path and keeps the original spelling when that
spelling is within the name allowance. Component and path lengths include the
`.deno-*` suffix of the stored regions a member has. A descendant has no source
path when an ancestor spelling was not retained. Cancellation is checked before
the virtual-filesystem walk. The walk does not yield, so it does not observe a
cancellation that arrives while it is running; the retained allowance bounds its
work. The combined logical path tree admits at most 250,000 distinct prefixes.
`MAX_DENO_RETAINED_BYTES` admits at most 256 MiB of retained header and entry
metadata. The shared artifact expansion budget also bounds the sum of referenced
member lengths, with a 256 MiB floor.
Carrier location claims a file only after it confirms the carrier name: a
Mach-O `__SUI` segment, a `SUI` ELF note descriptor named `d3n0l4nd`, a PE
`D3N0L4ND` resource, or an Intel trailer opening with `d3n0l4nd`. Before that,
malformed tables and exhausted search budgets leave the file with native
inventory, and that inventory makes no claim that the file holds no Deno
section. ELF location reads ELF and note headers, not the whole image, and does
not hash note descriptors. An ELF larger than 512 MiB is still located when
those headers fit. Program and section tables are read at their canonical record
size, so the 16-bit header count bounds each read at 65,535 records. A table
that cannot be read, or that uses extended program numbering, is skipped and
another table can still hold the note. At most 256 notes are examined
(`MAX_INSPECT_ELF_NOTE_ENTRIES`). A damaged table or the note ceiling is a
refusal only when a `SUI` note was also confirmed. Intel Mach-O trailer search
reads each scanned byte at most once and examines at most 64 `<~sui-data~>`
sentinels (`MAX_DENO_INTEL_TRAILER_SENTINELS`). The search continues past a
confirmed trailer, because an enclosing trailer can hold it as a stored file, so
reaching that allowance after a confirmation is a refusal. PE location walks the resource directories to the named payload and
does not read the image whole, so a PE of any size is located when the
`D3N0L4ND` payload is within the 512 MiB resource reader ceiling. A larger
payload, or a confirmed resource that cannot be resolved, is a named refusal.
Refusals name the boundary. There is no runtime override; additional host memory
or `NODE_OPTIONS` does not raise these ceilings. Duplicate-section verification
rejects unequal lengths before hashing, stops at the first digest mismatch,
and reads at most the carrier file size in aggregate
payload bytes. Overlapping copies that exceed that allowance are refused.
Environment-file values and CA certificate bytes are retained in local Evidence
with their counts and byte lengths. The npm snapshot length is retained and its
bytes are not decoded.
+55 -14
View File
@@ -47,6 +47,17 @@ computer would not have that entry. An `--executable` runs from
the current directory, as it would from a shell, and a relative path to it is
resolved there.
A nested desktop file uses a dashed ID: `vendor/app.desktop` has ID
`vendor-app`. REA checks path spellings that can encode that ID within each
XDG root before trying the next root. Unrelated directories do not affect
selection. If an applicable path cannot be examined or the bounded search
cannot establish absence, capture reports an incomplete desktop-entry search
rather than selecting a different application from a later root.
Desktop-entry string values retain literal trailing spaces. For example,
`Path=/tmp/workspace ` and `Path=/tmp/workspace\s` name the same directory
ending in a space. Use the escaped spelling to make such a suffix visible.
Before writing anything the command refuses to start if a window of the
application is already open, or if the window list cannot be read. A launch
beside a running instance can hand off to it, and that instance's unsaved
@@ -56,6 +67,9 @@ environment, and reads commands from stdin, one per line. The application gets
REA's environment without the `AGENTENV_*` variables an agent environment sets,
such as its control token: an app the exported computer launches never has
them, and an app captured inside a computer must not hold a credential to it.
It also gets `LIBC_FATAL_STDERR_=1`, so glibc writes a fatal error, such as
an abort's reason, to the app's stderr rather than its terminal, and an app
that exits at launch reports it.
| Line | Effect |
| ------------------------------------------- | ----------------------------------------------------------- |
@@ -90,12 +104,20 @@ Progress lines on stderr are JSON, `{"rea_progress": {"phase":
"desktop_capture", "message": ...}}`. Those a driver waits on also carry an
`event`: `{"kind": "window_open"}` once the window opens; `{"kind":
"checkpoint", "name", "trigger", "at_ms", "entries", "changes",
"retained_files", "retained_bytes"}` once a checkpoint has been taken, the
baseline, `stop` and `exit` included, with the paths walked, the paths
changed since the checkpoint before and the files retained; and `{"kind":
"checkpoint_refused", "name", "reason"}` for a requested name it refused. A
driver that sends `checkpoint <name>` waits for the event naming it rather
than for a fixed time.
"retained_files", "retained_bytes", "changed_files", "more_changed_files"}`
once a checkpoint has been taken, the baseline, `stop` and `exit` included,
with the paths walked, the paths changed since the checkpoint before, the
files retained, and up to ten of the files (not folders) that changed,
home-relative: those under a `--state-path` or absolute `--argument` first,
then those the application held open, then those in its state directories,
then the rest, and last caches (a folder whose name ends in `cache`, such as
`~/.cache`) and WebKit or Chromium storage, each by path, with a count of the
rest. An application can rewrite dozens of cache files on a save, and KDE's
holds its service cache open, so the saved document would otherwise fall past
the ten;
and `{"kind": "checkpoint_refused", "name", "reason"}` for a requested name it
refused. A driver that sends `checkpoint <name>` waits for the event naming it
rather than for a fixed time.
When the session ends the capture sends SIGTERM to the launched process, its
process group and every process that carries the run token, waits up to five
@@ -107,7 +129,11 @@ remain. Interrupting the command (Ctrl-C) ends the session the same way
without a further checkpoint; the capture is still written with end reason
`cancelled`, and the command exits with status 130. Interrupted before the
application is launched, the command writes no capture and removes the
content it had retained.
content it had retained. If cancellation arrives during publication or final
cleanup, the already-written capture can instead retain its earlier end
reason. Inspect `capture.json` and the error's `details.partial_observation`
for the retained capture Evidence. Cleanup failures also report resources
that could not be released.
If the capture fails for any other reason before `capture.json` is written,
the application is closed the same way and the content already retained is
@@ -302,20 +328,29 @@ dot-folder named after the package, the executable, the desktop entry's full
id and its last part, and the entry's name, with whether each existed at the
start. A folder in those places whose name is one of these in another letter
case joins them, such as GIMP's `~/.config/GIMP` for the `gimp` package; only
the whole name is compared, so `~/.config/GIMPshop` does not. Dotfiles in the
the whole name is compared, so `~/.config/GIMPshop` does not. A file under a
folder the application creates during the capture beside one of them, with
the same name in another letter case or with a version added (`-3.1` or
`3`), as TreeLine's `~/.treeline-3.1`, is its state too. Dotfiles in the
home named after the application (`.<name>rc`, or
`.<name>` followed by `-`, `.` or `_`, for a name of three or more characters)
that exist at the start join them, since an application may only read such a
file during the capture. A `flatpak run` launch is named after its application
file during the capture. So does KDE's settings file in the config folder,
`<name>rc` such as Tellico's `~/.config/tellicorc`, for each such name of three
or more characters, whether or not it exists yet. A `flatpak run` launch is named after its application
id rather than the `flatpak` launcher, and adds `~/.var/app/<id>`.
**Session.** When it started, how long it ran and why it ended; the launched
process's exit status; every process seen in the application's tree; every
client window with its class pair, titles, owner pid and type, marked when it
belongs to the application; when the first application window appeared; the
belongs to the application. Titles and class names decode xprop's quoted
delimiters, newline and tab escapes, and three-digit octal byte escapes;
unsupported escape spellings leave that string unknown rather than inventing
text. The session also records when the first application window appeared; the
most common class pair of the application's windows, for matching its window
later; files the application's processes held open under the walked roots; the first
8 KiB of the launched process's stderr; and whether cleanup was verified. Each
later; files the application's processes held open under the walked roots; the last
8 KiB of the launched process's stderr, where a failing app's last words are,
with `stderr_truncated` when earlier output was dropped; and whether cleanup was verified. Each
process records whether the capture started it: the launched process, a
process carrying the capture's run token, or a descendant of one, even when
its environment cannot be read, as for a zombie or a sandboxed renderer.
@@ -341,7 +376,9 @@ directory, which are named in the limitations instead; a selected path that is
not a directory brings the `-wal` and `-journal` paths beside it, so a database
selected on its own is captured with its logs), the state directories
as walked (their physical spelling, which differs from the inventory's when one
is a symlink), the paths every walk left out (the output folder and
is a symlink), the selected paths (each `--state-path` and content-root
`--argument` as named, absolute, beside the physical path walked, so a
symlinked settings folder keeps what its name means), the paths every walk left out (the output folder and
`--exclude` values), and the checkpoints in order: `baseline` before
launch, each requested checkpoint, `stop` or `time-limit`, and `exit` after the
application has gone. Each checkpoint records how many paths its walk saw,
@@ -370,7 +407,11 @@ unreadable SQLite sidecar from an absent one. Captures made before this field
was added must be made again before state inspection, task drafting or export.
Directories the application held files open in, but whose starting content was
not retained, are listed so a second capture can pass them with
`--state-path`.
`--state-path`, or `state_paths` on a build computer's `start_build_capture`,
and a limitation names them, spelled from `~/` under the home. A lock file
the application held open, such as Poedit's `~/poedit.lock` or Lucene's
`write.lock`, makes no folder such a directory, since it holds nothing to
retain.
**Limitations.** What the capture could not establish, such as a truncated
walk or a missing window.
+251 -29
View File
@@ -15,13 +15,28 @@ agent-env run ./mousepad-bundle --dry-run
The export reads the capture and its [state view](desktop-application-state.md);
it does not run the application. `--name` sets the environment name; otherwise
it comes from the desktop entry id or the program, with an `app-` prefix when
it comes from the desktop entry id or the program: a reverse-DNS id's last
part (`org.xfce.mousepad` gives `mousepad`), or else the whole id without a
trailing version (`glabels-3.0` gives `glabels`), with an `app-` prefix when
that name would not be a portable bundle name (for example all digits). The
output directory must be new or empty. `--task` adds a task an agent wrote for
the capture, once REA has validated it against the capture; see
[desktop application tasks](desktop-application-tasks.md). `--package-url`
says where the computer downloads the package of an application installed from
a `.deb` file; see [Applications from a .deb file](#applications-from-a-deb-file).
`--download-install FILE` says which AppImage or tarball a build computer
unpacked the application from; see
[Applications from an AppImage or tarball](#applications-from-an-appimage-or-tarball).
`--extra-package NAME`, repeatable, installs another Ubuntu 24.04 archive
package beside the application, such as a runtime piece its package does not
install; a [build computer](desktop-build-witness.md) passes its request's
`extra_packages`, or a `.deb` request's `dependencies`, this way. A name that
is not a Debian package name is refused (`extra_package`). Names the bundle
installs anyway, the application's own package and the dependencies it names
for a package installed from its `.deb` file, are not repeated; the rest are
listed in the limitations and the README. A package the captured `.deb` lists
as one alternative, such as `openjdk-17-jre | java-runtime`, is kept when apt
installs the application by name, since apt may satisfy it with another.
`--seed-checkpoint` names the checkpoint whose state seeds the bundle, the
baseline by default, and `--end-checkpoint` the one a task must pass on, the
capture's last by default; see [The seed checkpoint](#the-seed-checkpoint).
@@ -33,8 +48,10 @@ The command returns Evidence with operation `export_desktop_application` and
predicate type `rea.desktop-application-export`, listing the environment name,
the seed and end `checkpoints`, owned paths, seed files, the seeds it
rewrote to remove the capture host's name and user (`scrubbed_files`), the
bundle files that still hold them (`unscrubbed_files`), and written files,
the last three by their path in the bundle. A failed export, cancellation
gzip seeds it compressed again only to clear their headers
(`recompressed_files`), the bundle files that still hold them
(`unscrubbed_files`), and written files, the last four by their path in the
bundle. A failed export, cancellation
included, removes the bundle it had not yet published, so no partial copy of the
user's data remains. If the bundle was published but its output handles could
not be closed, the command reports a cleanup error that carries the export
@@ -42,17 +59,19 @@ Evidence; the bundle itself is complete.
## The bundle
| Path | Contents |
| -------------------------------- | -------------------------------------------------------------------------------------------------- |
| `envs/<name>/env.toml` | `type = "computer_app"`, the module and class, `computer = "ubuntu-24.04"`, `driver = "reference"` |
| `envs/<name>/<file>.py` | The `ComputerAppEnvironment` class |
| `envs/<name>/SKILL.md` | What the app is, its window class and where its files live |
| `envs/<name>/seed/` | The application's files at the seed checkpoint, by home-relative path |
| `envs/<name>/apt-keys/` | The signing key of each vendor apt repository the app installs from |
| `envs/<name>/install-package.sh` | With `--package-url`: the run script that installs the downloaded package with dpkg |
| `tasks/smoke.json` | A task that deploys the app |
| `tasks/<task>.json` | With `--task`: the agent's task, its verifier in `artifacts/` and the eval in `evals/` |
| `README.md` | What was exported, from which capture, and what to keep in mind |
| Path | Contents |
| --------------------------------- | -------------------------------------------------------------------------------------------------- |
| `envs/<name>/env.toml` | `type = "computer_app"`, the module and class, `computer = "ubuntu-24.04"`, `driver = "reference"` |
| `envs/<name>/<file>.py` | The `ComputerAppEnvironment` class |
| `envs/<name>/SKILL.md` | What the app is, its window class and where its files live |
| `envs/<name>/seed/` | The application's files at the seed checkpoint, by home-relative path |
| `envs/<name>/apt-keys/` | The signing key of each vendor apt repository the app installs from |
| `envs/<name>/install-package.sh` | With `--package-url`: the run script that installs the downloaded package with dpkg |
| `envs/<name>/install-download.sh` | With `--download-install`: the run script that unpacks the downloaded AppImage or tarball |
| `envs/<name>/applications/` | With a tarball's `--download-install`: the desktop entry REA wrote for its program |
| `tasks/smoke.json` | A task that deploys the app |
| `tasks/<task>.json` | With `--task`: the agent's task, its verifier in `artifacts/` and the eval in `evals/` |
| `README.md` | What was exported, from which capture, and what to keep in mind |
The class file is `<name>_app.py` with hyphens as underscores, for example
`mousepad_app.py`: agentenv imports it under its stem, so a plain `<name>.py`
@@ -62,9 +81,10 @@ an `App` suffix.
The class declares:
- `Packages(apt=[...])` with the package the capture found. A vendor package
is named `<package>/<release>`, its repository's release (the Suite apt
reports as `a=`, or else its Codename), so apt takes it from that repository
- `Packages(apt=[...])` with the package the capture found, then the
`--extra-package` names. A vendor package is named `<package>/<release>`,
its repository's release (the Suite apt reports as `a=`, or else its
Codename), so apt takes it from that repository
even when the Ubuntu archive offers a higher version or epoch, as noble's
transitional `firefox` does over packages.mozilla.org's; it is named alone
when the release names neither, or when the capture was written before
@@ -104,7 +124,8 @@ The class declares:
reason (a capture
written before restrictions were recorded counts as unrestricted); when
another usable repository lists the same version it is left out instead,
with a limitation. The export also refuses snaps, flatpaks, AppImages, and a
with a limitation. The export also refuses snaps, flatpaks, an AppImage or
tarball not named with `--download-install`, and a
package no recorded repository lists unless it was installed from a `.deb`
file the capture recorded and `--package-url` is given, since the computer
could not install them by name, and a capture written before credentials
@@ -145,7 +166,8 @@ The class declares:
README and the result's limitations say the sandbox is off.
- `paths`: the state directories holding the application's state files and the
folders holding its documents, nested folders collapsed. A folder beside a
state directory whose name differs from it only in letter case is owned
state directory whose name differs from it only in letter case, or that
adds a version, as TreeLine's `~/.treeline-3.1` beside `~/.treeline`, is owned
whole in the files' spelling, so a `~/.config/GIMP` profile GIMP created
during the capture beside the candidate `~/.config/gimp` is owned as
`.config/GIMP`, not as the folder of its first file. The home itself and
@@ -154,9 +176,11 @@ The class declares:
Files the capture recorded under a symlinked state directory's physical
spelling are mapped back to the innermost such directory's home spelling,
unless that spelling is outside the captured home, as when the home itself is
a symbolic link. When two files map to one home path, the export uses the one
present before the capture, else the first by path, and a limitation names
the other.
a symbolic link. When a selected link names an application state directory,
the bundle seeds the application's state path and restores the selected
alias at boot. Selections nested under that alias are seeded under the same
state path. An existing incompatible alias stops setup without replacing it. When two files map to one home path, the export uses the one present
before the capture, else the first by path, and a limitation names the other.
- Data hooks, because declaring any hook switches off agentenv's default data
plane: the class seeds the home once per boot and keeps it as the initial
state with `keep_initial`, `data/add` and `data/reset` call agentenv's `add`
@@ -169,10 +193,76 @@ retain is not seeded: one in the state view without retained content at that
checkpoint, or one the capture omitted (for example too large or past the
content budget). The result lists them in `unseeded_files` and the README
names them. When the application held files open in folders whose starting
content the capture did not retain, a limitation names those folders. The
desktop Trash, `~/.local/share/Trash`, is never the application's, so a file
the user moved there is neither owned nor seeded, even when a window title
names it; a limitation lists the files the Trash held at the seed.
content the capture did not retain, a limitation names those folders, spelled
from `~/` under the home: a file there is seeded only when the capture
retained it, as it does one written during the capture, and the limitation
names the seed files there or says there are none. The desktop Trash,
`~/.local/share/Trash`, is never the application's, so a file the user moved
there is neither owned nor seeded, even when a window title names it; a
limitation lists the files the Trash held at the seed.
Files that changed during the capture outside the owned paths are neither
owned nor seeded, so the app starts without what it saved there: MuseScore
keeps its settings in `~/.config/MuseScore`, which its name rules miss, and
showed its first-run wizard on every boot. A limitation and the README name
those folders, leaving out desktop services' files, each collapsed to its
folder in `~/.config`, `~/.local/share`, `~/.local/state` or `~/.local`, the
hidden folder of the home it lies in, or else its own folder, up to eight and
a count of the rest. Capture again naming them with `--state-path`, or
`state_paths` on a build computer, to own them.
Lock files the app holds while it runs are left out of the seed: a copied one
makes the app find its profile or document in use, and a LibreOffice Calc
bundle whose seed held its profile's `.lock` showed no window at boot. They
are `lockfile`, `lock`, `.lock`, `.parentlock`, `parent.lock`,
`SingletonLock` and Lucene's index lock `write.lock` anywhere, as Poedit's
translation memory holds, LibreOffice's document lock `.~lock.<name>#`, a
`<file>.lck`, `.<file>.lock`, `.<file>.lck` or `<file>.<ext>.lock` beside a
file the capture recorded in the same folder, such as GnuCash's
`household.gnucash.LCK`, Grisbi's empty `.household.gsb.lock`, which made it
refuse every save, and VYM's `plan.vym.lock` (a project's `Gemfile.lock`
beside its `Gemfile` has no extension to its file, so it is seeded), and
`*.lock` or `*.lck` directly in the home, as wxWidgets' single-instance
`~/poedit.lock`, or directly in one of the application's state directories;
a lone `notes.lck` or `.notes.lock` elsewhere is seeded. A lock
never makes a path the application's own, so `~/poedit.lock` is neither owned
nor named among the folders the bundle does not own.
Elsewhere such a file may be a project's own, such as `Cargo.lock` or
`yarn.lock`, which pin dependencies, and is seeded, even under a folder whose
name starts with a dot. A file the state view makes a document, or one named
itself by `--state-path` or an absolute `--argument`, is never left out,
whatever its name. A limitation and the README list them, up to
eight and a count, after "Left out of the seed". They stay under the owned
paths, so `data/get` returns the lock the running app holds, and `data/reset`
restores the seed without them.
A seed file keeps the permission bits it had at the seed when the capture saw
it change, such as a `0600` file an app checks: the class module lists those
other than `0644` in `SEED_MODES`, and the first boot sets them when it copies
the seed. A file the capture never saw change has no recorded mode and is
written `0644`.
Files in app state are retained regardless of a `.log` extension or `log.<n>`
name. They can hold conversation history or database writes as well as
diagnostics. The normal host-identity scrub applies to retained text; filenames
alone do not identify disposable diagnostics. Locks beside these files follow
the lock rules above.
Other seed files the app keeps for its own
running are seeded as captured and named, collapsed to the folder that holds
them: WebKit or Chromium storage (such as `hsts-storage.sqlite`, `storage/`,
`mediakeys/`, `Local Storage/`, `IndexedDB/`, `Cookies`, `Visited Links`,
`Platform Notifications/`, and a whole `QtWebEngine/`
profile), which may hold the app's own data, and caches (a folder whose name ends in `cache`); a stale one
can change how the app starts. A seeded LibreOffice profile's
`registrymodifications.xcu` ships without its `RecoveryList` items, which
LibreOffice writes for the documents it has open and which would start the
bundle into document recovery instead of its window; a limitation and the
README name the file. REA finds the items with its XML parser, as `item`
elements whose `oor:path` is `/org.openoffice.Office.Recovery/RecoveryList`
however the tags are spelled, and cuts exactly those elements, so text in a
comment or CDATA and every other byte stay as captured. A registry that is
not well-formed XML ships unchanged.
The application's dconf keys at the seed, if any, are written once when the
app first starts, also for an application that owns no files, and the class adds
@@ -182,7 +272,14 @@ existing user database through a `file-db:` profile, then runs `dconf compile`
on that dump and the captured keys, in that name order so the captured keys
win, and replaces `~/.config/dconf/user`. If that fails, the server prints a
one-line warning and the app starts without the captured keys. `data/reset` does
not restore them.
not restore them. No file of the bundle holds them, so `data/get` does not
return them and no task check reads them; a draft whose only change between
its checkpoints is to the application's dconf keys says so with
`uncheckable_changes`, and one whose dconf database changed but could not be
read says so with `unreadable_changes`. When a dconf database changed by the
seed checkpoint but its version there could not be read, as without
`dconf-cli`, the export seeds no keys from it and a limitation names it with
the read error.
## The seed checkpoint
@@ -209,6 +306,39 @@ tell the two apart, so the flag is the caller's word. `export_build_environment`
passes it, since the building agent makes the seed in the build computer. The
Evidence records it as `synthetic_seed`.
## Withheld sign-in state
`--withhold-from <checkpoint> --withhold-to <checkpoint>` withholds every file
under the owned paths that changed after the first checkpoint up to the
second, as the capture recorded its changes; `--withhold-path <file>` adds a
home-relative file, such as one written at first launch. The draft
(`describe-desktop-application-task`) takes the same options, leaves those
files out and lists them as `withheld_files`; the export refuses a check that
names one. Each withheld file present at the seed is left out of
`envs/<name>/seed/` and becomes a secret setting:
- the class declares `Settings` with a `SecretStr` field per file, and
`WITHHELD`, each field's home path;
- `env.toml` sets each field to `env:REA_<APP>_<FILE>`, so agentenv refuses
the deploy, naming the variable, until it is set;
- at first boot, before keeping the initial state, the class writes each file
from its setting, the file's bytes in base64, mode `0600`, so `data/reset`
restores it, and `data/get` serves it neither as a part nor in the views;
- the README names each variable, with
`export REA_<APP>_<FILE>="$(base64 -w0 < ~/<file>)"` from the receiver's
own signed-in copy of the app.
A withheld file larger than 48 KiB is refused, since its base64 must fit one
environment variable. `--withheld-copy <folder>` copies the withheld files,
as captured, into a new or empty folder outside the bundle. The result lists
them as `withheld_files`, each with its `setting`, `variable` and `handle`.
`--consent <file>` ships the person's consents, a `consent.json` that
`record_build_consent` records, as the bundle's own `consent.json`.
`--seed-withheld` seeds the withheld files after all, refused unless that
file holds a `seed_sign_in` consent; the result lists them as
`consented_files`, and the README says they are there with consent.
## Host name and user
A seed can hold the capture host's name and the user's: Geany saved its mail
@@ -252,6 +382,28 @@ export removes them from what the bundle ships:
boot, as it did the captured home before. The replacements read as the
computer's own: its user is `user`, with its home in `/home/user`, and
`localhost` is the name every host has for itself.
- A gzip-compressed seed, such as a Gnumeric workbook, is decompressed, up to
256 MiB, scrubbed as the format the state view read its document as, and
compressed again whether or not its document changed, so no file name,
comment or time its header held ships: with no file name, comment or extra
field, modification time 0 and the operating system unknown, so the same
document gives the same bytes on every host. It is deflated at the fastest
level, or stored when deflating would make it expand more than the 100 times
a view reads, so a seed that read still reads. It is listed in
`scrubbed_files` when its document changed, and otherwise in
`recompressed_files`, which the README counts rather than lists, so the
example and template files an app copies on first run do not bury the
document scrubbed; one already in that form ships as captured. The class copies it at
boot as it is, so the home it holds stays `/home/user`. One that does not
decompress within the scrub limit ships as captured, its bytes searched.
A document the state view did not read can still be decompressed and
recompressed under the separate 256 MiB scrub limit; its content is searched
even when its format cannot be scrubbed. One whose document needs no edit but a member of
which has an extra field, where BGZF (`.vcf.gz`, `.bam`) and dictzip
(`.dict.dz`) files index their blocks, also ships as captured, its bytes
searched, so its blocks stay where its index says; one whose document
changed is still compressed again as one member, losing them, as the
export's limitation says.
- Binary files, SQLite databases among them, and text files over 256 MiB are
copied as captured. Then every file the bundle ships, the class module with
its dconf keys and the README included, is searched by a looser rule than
@@ -318,6 +470,73 @@ declared vendor repository installs the package already; when the URL is not
written as `http://` or `https://` or holds a user name or password; and when
the file is built for an architecture other than `amd64`, `arm64` or `all`.
## Applications from an AppImage or tarball
A [build computer](desktop-build-computer.md) can install an application from
its project's AppImage or tarball, pinned by URL and SHA-256, under
`/opt/rea-apps/<desktop entry>`. Neither holds a Debian package, so the
capture records the package as `unknown`, and the export takes the install
from `--download-install`, a JSON file the build computer writes from its
request:
```json
{
"kind": "appimage",
"desktop_entry": "org.freecad.FreeCAD",
"url": "https://github.com/FreeCAD/FreeCAD/releases/download/1.1.4/FreeCAD_1.1.4-Linux-aarch64-py311.AppImage",
"sha256": "675d1a4295b2183e0e1d816a4b5557dcb63aeced4e60aaa28d6c3686f4c71dc9",
"architecture": "arm64"
}
```
A tarball's adds `program`, its path inside the archive, and optionally
`name`. The class then declares
`downloads=[Download(url=..., sha256=..., to="vendor/app.AppImage", arch=...)]`
(`vendor/app.tar` for a tarball) and `run=[RunScript(script="install-download.sh")]`,
the same script the build computer ran, with no apt package for the app. The
bundle does not contain the application and supports only the download's
architecture; the URL must keep serving those bytes, and the application's
licence is the operator's to check.
The export refuses the file (`download_install`) unless it names an
`appimage` or `tarball` with an `http://` or `https://` URL and a SHA-256,
the capture launched its `desktop_entry`, the captured program lies under its
folder in `/opt/rea-apps`, and the capture ran on its architecture; it
refuses `--package-url` beside it.
## Grading once the app has saved
A task's verifier, `artifacts/<task>-check/verify.py`, grades the app's files
only once they have settled, because an app can save on its own timer after the
last change. Gnote saves a note 4 s after the last key, so a read taken as
soon as the agent stops finds the text on screen but not yet in the file. The
verifier reads the app's `data/get` every 0.5 s. It compares each file's bytes
between reads by their SHA-256, as `data/get` returns them, and grades once
every file has held for 3 s. The 3 s count from when a read returned the
current bytes, not when it began, so a slow read that brings a change late
does not count its own run as quiet. 15 s after the first read began, the
bound, the verifier grades the last completed read: no read starts at or
after the bound, and a read still running then is cut. Each result records
whether the files settled in `settled`, and whether the bound cut a read in
`read_cut`.
The window has a cost and a limit:
- An app whose files do not change during the check, such as one that saved
at once, is graded 3 s after the first read returns.
- A save that lands more than 3 s after the first read returns is still
missed. An app that saves 4 s after the last key is caught only when the
agent stops at least a second after that key.
- Files the app rewrites more often than every 3 s, such as a log, never
settle, so every check waits until the bound.
- The bound counts the reads too, so a slow `data/get` ends the check at
15 s. Only the first read, which every grade needs, runs to its own
timeout.
The bound and window are `SETTLE_BOUND_S` and `SETTLE_WINDOW_S` in the
verifier. `check_build_task` waits the same way before it grades each
witness stage; see [witnessing](desktop-build-witness.md#witness).
## Typed views
The views follow the [state view](desktop-application-state.md)'s formats and
@@ -332,7 +551,10 @@ as their entries, read with Python's `zipfile` from the file in place, with
REA's entry, size, compression ratio and archive limits and its wording for an
entry it does not read. The module reads the central directory itself, as REA
does, and shows `zipfile` only the records it lists, reading each entry in
bounded chunks no further than a byte past its declared size. A JSON file
bounded chunks no further than a byte past its declared size. A gzip file is
the view of the document inside it, with `"compression": "gzip"` beside its
format, decompressed with Python's `zlib` within the same entry size and ratio
limits, its members joined as REA joins them. A JSON file
holding a number JavaScript cannot read exactly, such as an integer above 2^53,
or whose retained value nests more than 500 levels deep, gets an `error` instead of a view, as in
REA. Duplicate keys keep their last value before the depth check. Text that is not one JSON
@@ -363,5 +585,5 @@ when a DOCTYPE names a DTD. Known differences remain:
Unless it was [made for the task](#a-seed-made-for-the-task), the seed is the
user's real data. Keep the bundle local and do not publish it.
The class was checked against agentenv-framework 0.9.1431 with
The class was checked against agentenv-framework 0.9.1464 with
`python -m agentenv_protocol.computer._declare` and `agent-env run --dry-run`.
+60 -4
View File
@@ -25,7 +25,7 @@ changed later. Each path records the evidence the capture holds about it:
| ------------------------ | ------------------------------------------------------------------------- |
| `state_directory` | It lies in one of the application's state directories, in either spelling |
| `opened_by_application` | An application process held it open during a sample |
| `named_in_window_title` | An application window title spelled its name or `~/` path on its own |
| `named_in_window_title` | An application window title spelled its name, `~/` or absolute path whole |
| `selected_path` | It lies under a `--state-path` or absolute `--argument` of the capture |
| `dconf_application_keys` | It is a dconf database holding groups whose path names the application |
| `desktop_service` | It lies where desktop services and toolkits keep shared files, or caches |
@@ -40,11 +40,26 @@ The role follows from the reasons, in this order: `shared_desktop` for a file
in the desktop Trash, which the user deleted, whatever else names it;
`application_state` for application keys in dconf, or a state directory outside shared desktop
locations; `document` for a file named in a window title or selected by the
caller, even if the application holds it open; `application_state` for another
caller, even if the application holds it open, except that a selected file
under a hidden folder of the home, such as `~/.config/MuseScore`, a dotfile
there, or a lock an application holds, such as LibreOffice's `.~lock.<name>#`
beside a document, is `application_state`, judged by the path as the caller
named it, so a file reached through `~/.config/MuseScore` stays the application's
when that folder is a link to `~/settings/MuseScore`; the innermost selected
path holding a file decides, so a score selected itself inside the link's
target keeps its own name and is a document (a capture written before it
recorded selected paths is judged by their physical spelling);
`application_state` for another
open file outside shared locations; `shared_desktop` for other files in shared
locations; `unrelated` otherwise. A window title names a file only when no
other file name character adjoins the name, so `day.txt` does not match
`today.txt - Notes`.
`today.txt - Notes`, and never by a folder of a path the title shows: in
CherryTree's `home-notebook.ctd - /home/user/Documents - CherryTree 1.1.2`,
`user` names no file. A name without an extension, such as `Makefile`, must
also stand on its own rather than end a longer path, as in
`Makefile - Editor`. A file under `~/.cache` or `~/.config/dconf` is never
named by a title. The capture's checkpoint acknowledgements rank files by the
same rule.
Application names, which select dconf groups, come from the package, the
executable, the desktop entry's id and `StartupWMClass`, and the window match.
@@ -70,11 +85,21 @@ whether the file was present, the SHA-256 of its retained bytes, and a view:
| `dconf` | The `GVariant` header | Groups whose path names the application, plus the names of the other groups |
| `zip` | A zip local file header, `PK\x03\x04`, whatever the name | Its file entries in archive order, each with its own format and view |
| `json` | A `.json` name or a leading `{` or `[` that parses | The parsed value, from files up to 4 MiB nested up to 500 levels |
| `xml` | An XML name or declaration that parses | An element tree (`name`, `attributes`, `children`); text kept exactly, DTDs never read |
| `xml` | An XML name, a declaration or a leading element that parses | An element tree (`name`, `attributes`, `children`); text kept exactly, DTDs never read |
| `keyfile` | Only `[group]`, `key=value` and comment lines, with at least one group | Groups of `key` → string value, from files up to 4 MiB |
| `text` | Other UTF-8 text | Lines, up to 5,000 |
| `binary` | NUL bytes or invalid UTF-8 | None |
A gzip file is read as the document inside it; see
[compressed documents](#compressed-documents).
Text that opens with an element, such as a Freeplane map's
`<map version="freeplane 1.7.0">` with no declaration, or with a DOCTYPE that
has no internal subset and then an element, such as a KmPlot plot's
`<!DOCTYPE kmpdoc>` before `<kmpdoc version="4">`, is XML when the whole text
is well formed, whatever the file is called, a `.txt` file included;
otherwise it stays text. The exported verifier makes the same choice.
A JSON value holding a number JavaScript would round, such as an integer above
2^53, is not read rather than shown rounded.
@@ -193,6 +218,37 @@ so an archive of hundreds of thousands of entries costs no more to read
than one of a thousand. An archive whose central directory cannot be read has a
`view_error` of its own.
## Compressed documents
Gnumeric's `.gnumeric`, Dia's `.dia`, Xournal++'s `.xopp`, GnuCash's default
book and Inkscape's `.svgz` are XML compressed with gzip. A file that starts
with gzip's magic bytes, `1f 8b 08`, whatever its name, is read as the
document inside it: its members joined, then given a format and view by the
rules above under the file's own name, so a pointer or check into it is
written exactly as for the same document uncompressed, and the task draft is
the same. The version records the compression beside the format:
```json
{
"format": "xml",
"compression": "gzip",
"view": {
"root": { "name": "gnm:Workbook", "attributes": {}, "children": [] },
"truncated": false
},
"view_error": null
}
```
The document is read only when it is at most 16 MiB and at most 100 times the
file's size, an archive entry's limits, so decompressing stops there; past
them, or when the stream is damaged or cut short, the version has `format`
null and a `view_error`, and a check into it is undecided. A SQLite or dconf
database inside keeps its format and has a `view_error`, an archive inside is
read as an archive, and another gzip stream inside is binary. A gzip file
inside an archive reads as binary. Other compression, such as xz, Zstandard
or bzip2, is not read: such a file is binary.
## Kinds of change
Between consecutive versions a change is `created`, `deleted`, or a
+547 -43
View File
@@ -42,35 +42,457 @@ operation `describe_desktop_application_task` and predicate type
database is compared by its rows, since its hash leaves out the `-wal`
file. Text changes list each line
once and add `line_counts`, the lines found at both ends whose number of
occurrences changed. Views appear only for the files the suggestions cover,
with arrays past 200 items and strings past 2,000 characters cut
occurrences changed. An XML file's change names its members by the
[selectors](#pointers-and-selectors) checks use, as an archive's already
does, and by position only where nothing names a member or where only the
members' order changed. Views appear only for the files the suggestions
cover, with arrays past 200 items and strings past 2,000 characters cut
(`view_cut`).
- `values`, in each of those files: the values its change added, changed and
removed, each with the `pointer` a check names it by, its `kind` (`added`,
`changed` or `removed`), and `before` and `after`: the scalar, an element as
compact XML with the text the XML reader kept, spaces between runs included,
or a JSON value as compact JSON, cut at 600 characters, and null at the end
that lacks it. A file created or deleted lists what its one end holds,
`added` or `removed`: an archive's entries, an XML file's root element, a
JSON file's members or a key file's keys, each whole once. A value only
position reaches has `note: "by_position"`, and its pointer cannot go into a
check; noise an app writes as it saves has `view_state`, `renumbered`,
`volatile`, `timestamp`, `upkeep` or `layout` (see `task`). A record of
text fields added to a list of its kind, as GnuCash's
`<gnc:transaction>`, is listed field by field, and a field that lists
records, as its `<trn:splits>`, record by record, so the cut never hides
one. `refers_to` names up to
five other elements a value equals the `key` or `id` (`xmi:id` among them)
of, outside a view the app keeps of the document, as Umbrello's
`listview` mirroring its model by id, with the
`attribute` holding it, as HomeBank's `category="44"` names
`<cat key="44" name="Groceries"/>`, or the id a child element holds, as a
GnuCash split's `<split:account>` names the account whose `<act:id>` it
is, shown with its name, `<gnc:account …><act:name>Groceries</act:name>…`;
an element added whole lists those of the records of attributes it nests
too, as a KMyMoney transaction's splits name their `<ACCOUNT>` and
`<PAYEE>`, each once. Where several elements share that key, the one
whose tag shares the attribute's stem, as `payee` and `<pay>`, and of
those the one named for the attribute, as `account` an `<ACCOUNT>` before
an `<ACCOUNTID>`. A plain number names an element only through an
attribute so named or ending in `id`, `ref` or `key`, so a list's
`count="5"` names no `<FIXVERSION id="5"/>`. A value that changed lists,
in `alternatives`, its pointer naming the element by each other identifier
or name-like attribute it holds alone among its tag's members, up to
three, as an Inkscape text's `[@inkscape:label=Headline]` beside its
`[@id=text12]`, for a check to name it by instead; an element its tag
alone names inside the first one a condition names, as an EPUB chapter's
`h1`, by its `[@id=chapter-two]`. What a check can
name comes first, text an edit changed before the rest, so no cut drops
the edit, then what only position reaches, then noise. A file lists
at most 20 values and 8 KB, the draft 24 KB, and `values_cut` says when a
limit left some out. Values cover XML, archives, JSON and key files; a text
or SQLite file's change and suggestions already carry its lines and rows.
- `task`: a draft with the name `change`, a placeholder prompt the export
refuses, and suggested checks derived from the net change of the files with
role `document`, or of the app's own state files when no document changed.
role `document`, or of the app's own state files when no document changed,
excluding locks the export leaves out of the seed. App state files ending
in `.log` remain eligible for checks.
A text file gains `lines_present` for its new lines and `lines_absent` for
lines it lost (when either is at most ten), and `line_count` for each line
holding a letter whose count changed; JSON and key files gain
`value_equals` and `value_absent` by pointer; SQLite tables gain rows added,
holding a letter whose count changed; a new line holding an XML attribute
REA recognizes as generated, such as a named epoch time or `ID_329023692`, gets a
`line_count` of the lines `contains` its text up to that value, as
`<node TEXT="Water filter" ID="`, at the end's number, where both views
hold the whole file, instead of a `lines_present` another save would
fail, or a `volatile_lines` note when no text comes before it. UUID-shaped
text stays exact because its shape alone does not show that it was generated;
JSON and key files gain
`value_equals` and `value_absent` by pointer, a JSON array's records named
by an id field each holds alone at both ends (`id`, `uid`, `uuid`, `guid`,
`key` or a name ending in `_id` or `Id`), as `/lists/[id=chores]`,
whatever order the app saves them in; where the app generated that id, a
record both ends hold is named by its kind field and its first name-like
string field (a key ending in `name`, `title`, `label` or `caption`),
nearest first and up to three keys deep, that holds the same string at
both ends and names it alone at each, as TreeLine's category by
`/nodes/[format=CATEGORY][>data~1NAME=Science]`, and by its id where none
does, as `/nodes/[uid=7584d494d9f511f1a873edd4f1920549]` once its name
changed; and a record only one end holds is named by such a field that
names it alone at its end and nothing at the other, as TreeLine's new book by
`/nodes/[format=BOOK][>data~1Title=The Silk Roads]`, its other fields
checked through that selector and the fields the selector reads not, nor
a field holding what every like record (one of its kind) at the end holds
there, as the empty `children` of every book; and
by position only where nothing names a record, as a new book whose title
another book holds, with a `by_position` note listing those checks;
never a value that is a uid the app generates (a
GUID, or 32 hex digits as TreeLine's uuid1), nor a check the seed already
passes, as a new record's `format` where another record of that kind held
its place; a removed record is checked gone by its own pointer, as
`/lists/[id=chores]`, and only where the end holds nothing there, so a
record only position reached, whose place another took, is left to the
count; `member_count` checks of the
arrays whose members were added or removed, of the members' kind where
records share a `type`, `kind`, `format` or `category` field, as `/nodes`
matching `[format=BOOK]`, and a count guard of the innermost array an edit
went through, as for XML; SQLite tables gain rows added,
changed and removed, by primary key, and their new row count. An XML file,
and the JSON, key file and XML views of a zip archive's entries, gain checks
by [selectors](#pointers-and-selectors) and never through an element by
position: in XML, first [`text_equals`](#whole-text) for each element whose
text changed, then an element added whole that it exists, one removed whole
that it is absent, then values changed, added and removed, an entry or a
JSON value added whole through its members, and an empty array or object as
it is. The text check names the paragraph rather than a run inside it: it
goes up from an element sitting in its parent's text, and from one named by
its tag or position alone to the nearest ancestor named by an attribute, as
AbiWord's `p` by its `xid`; the text nodes and runs inside it get no other
check, but an element holding no text that is added or removed there, such
as an image or a line break, keeps its own, since the text check never
reads it. Whitespace an app lays out between elements is not checked, and
values that look like a time the app stamps, in ISO 8601 or as C's
`asctime` writes it (`Thu Nov 5 09:20:31 2026`), are left out.
text changed, then elements added or removed whole, then values changed,
added and removed, an entry or a JSON value added whole through its
members, and an empty array or object as it is.
- A selector names a member by its tag, then by its identifiers (`name`,
`id`, `xid`, `xml:id`), then by one other attribute, a name-like key such
as Scribus's `ANNAME` or `inkscape:label`, a worded value or an integer of
up to five digits first, then by two such attributes together, as
Gnumeric's cells by `[@Col=3][@Row=2]`, then by a coordinate, a long
number, a length with its unit, as `svg:height="2.629cm"`, an `xml:id`
or `draw:id` of the form `id2` that LibreOffice numbers anew as it saves,
so a Draw shape is named by its `draw:name`, or a token,
such as `XPOS` or `ItemID`, or an id of random case, as Umbrello's
`ubcgF2AWfBmHh` (`u` and twelve letters and digits), an automatic style name an app numbers as it
saves and renumbers on reload, as LibreOffice's
`presentation:style-name="pr1"` (`P1`, `T1`, `MT1`, `L2` on a
`*:style-name`), so a slide's frames are named by `presentation:class`,
or an attribute naming
view state, such as which layer is `selected`, and last by a child
element's text, `[>CHILD=VALUE]`, a name-like tag first, as Osmo's
record by `[>first_name=Delphine]`, MuseScore's `<Text>` by
`[>style=Title]`, a spreadsheet row by its label cell, or GnuCash's
transaction by `[>trn:description=Greenleaf Market]`: text of at most 64
characters, never a time or a token or id a program generates; then by
an identifier a child carries, `[>CHILD@ATTR=VALUE]`, as a GtkBuilder
`<child>` by `[>object@id=submit_button]`, never one an app generates or
numbers anew as it saves; and then by text a child joins from elements
of its own, as Glade's `[>packing=TrueTrue1]` from a widget's packing
properties, which moving the widget changes. A pair
counts every member holding both its values, whichever attributes that
member ranks first. An element with identifiers is named by those alone;
an id the app generates, as Freeplane's `ID_329023692`, or a GUID in
any attribute, braced or not, as VYM's `uuid="{18eadb5d-…}"`, ranks
last, after a child's text, so a new node is named by its `TEXT` and a
new VYM branch by `[>heading=Sunset boat tour]`, while a member
both versions hold pairs by such an id first, so records that keep their
UUIDs and swap titles read as two title edits. A value that stands for
none, as Grisbi's `Id="(null)"` on every transaction, names nothing, so a
new transaction is named by its `Nb`. A child's text is
counted on every sibling, one an identifier names included, so a title
two records share names neither. The selector must name the
member alone at both ends, with the same values; a child's text names a
member that is in one version only when the list's length changed, so a
row whose one cell an edit changed stays that row. An element whose one
identifier changed, at its place among its tag's members, with every
other attribute and its children alike, is that element renamed, as a
MyPaint layer renamed from `Layer` to `Sun`: it is paired by its first
other attribute naming it alone at both ends, as
`[@src=data/sun.png]`, so the rename reads as its `name` changed, and
the old name gets a check that it names nothing, unless its change is
noise, as an id the app renumbered. Where that attribute's values number
the members in document order, as MyPaint 2 writes `src` as
`data/layer-00.png`, `data/layer-01.png` and on along the stack and
renumbers them when a layer moves, each version is named by its own
value of the renamed identifier instead, `[@name=Sun]` and
`[@name=Layer]`.
- A child of the document's root that its tag alone names, and that holds
a list (two or more elements of one tag and no text of its own) and has
an identifier, also gets a condition that keeps it named if the app adds
a sibling of its tag, as Dia adds an empty `Background` layer each time
it reopens and saves a diagram: an id other than `name` both ends hold,
as Inkscape's `[name=g][@id=layer1]`, which a new sibling would not
share; else the text of a child both ends hold, as Dia's
`[name=dia:layer][>dia:object=#Receive order#]`, which an empty sibling
lacks; else its `name`, which a new one may repeat. Deeper, a member of
a list named for its tag, as Gnumeric's `gnm:Sheet` in `gnm:Sheets`,
holding elements and its tag alone naming it, gets an id, else a
name-like child's text, `[name=gnm:Sheet][>gnm:Name=Budget]`, else its
`name`. Other steps, and elements with neither, stay as they are.
An identifier the app numbers by position names nothing: where the
members of a tag hold it as 1..N (or 0..N-1) in document order at both
ends, members were inserted or removed, and every member another
attribute names alone at both ends kept its number or moved it the way
the count did, one at least, as Planner's task `id` after a task is
inserted, members are paired by their other attributes, so an insertion
reads as one task added. A value two members swap, or an id appended at
the end, as Tellico's next `<entry id="4">`, leaves the ids identity. An
identifier numbering the members 0..N-1 in document order at both ends,
where members came or went, as Parley numbers its `<entry id="6">` by
where it saves it, ranks after a child's text where a member has one, so
a new entry is `[>translation=library]` and its kept neighbours are named
alike; Tellico's ids, which count from 1, Tiled's and Rosegarden's,
whose members hold no text, stay identity. An element a change added that
holds nothing but the id of a record it added elsewhere, as Parley's
lesson membership `<entry id="6"/>`, is `upkeep`, listed with `refers_to`
on that record, never a check or a count.
- The text check names the paragraph rather than a run inside it: it goes up
from an element sitting in its parent's text, and from one named by its
tag or position alone to the nearest ancestor named by an attribute, as
AbiWord's `p` by its `xid`, unless it is a field its tag names in a
record of two or more fields holding text, as QElectroTech's `<text>`
beside `<info_name>` in a `<dynamic_elmt_text>`, or KmPlot's
`<equation-0>` beside `<arg-min>`, which is checked itself rather than
the record whose text joins its fields; one line of text the app lays
out between line breaks, as KmPlot's formula before the next element, is
checked, and its siblings guarded, with `normalize_whitespace: true`,
and text whose whitespace alone changed, as a formula the app moved to
an indented line of its own, gets no check; where no attribute names one, to the nearest
ancestor within three levels its tag names with no step by position, as
MuseScore's `VBox` around untitled `<Text>` elements; and where only
position reaches the element, to the ancestor above the outermost step by
position, by an attribute of its own that names it alone where one does,
as an ODS sheet's `table:table[@table:name=Q1 Sales]` above its rows. The
text nodes and runs inside it get no other check, but an element holding
no text that is added or removed there, such as an image or a line break,
keeps its own, since the text check never reads it. A decimal that is an
element's only text, such as a spreadsheet cell's, is checked by its
number instead. Free text that gains a line, such as a shopping list,
uses `text_equals` on the whole text: the current XML checks cannot
compare an unstructured line as a whole item. This can reject a correct
edit that puts the item elsewhere or changes spacing. Text an app keeps in an attribute, one element per run, as Scribus's
`<StoryText><ITEXT CH="Spring "/><ITEXT CH="Fair"/>`, gets a `text_equals`
with `text_attribute` on the nearest ancestor an attribute names, as
`[name=PAGEOBJECT][@ANNAME=Headline]` with `"text_attribute": "CH"`, where
that ancestor holds no text nodes and the attribute's holders are runs,
none inside another and none carrying an identifier or a name-like
attribute beside it, as Umbrello's `<ownedAttribute xmi:id="…"
name="email" visibility="private"/>`, a record whose attributes are
checked one by one, two or more or one holding words with a space: an
element's own attribute, as a Freeplane node's `TEXT` beside the nodes in
it, or a lone value, as `<Bool value="false"/>`, is checked where it is.
The check covers that attribute and the runs holding it; another change
in the frame, as a run's `FONT`, keeps its own check. A record added
or removed whole, an element holding only elements, its fields, such as
Tellico's `<entry>` or a record of repeated `<field>` elements, never
makes the list holding records of its kind a check, whose text would hold
the records the edit left alone, except a record removed whole that only
position names, whose absence only the list's text shows. Text made of
runs is no record: an element whose tag names a paragraph or a piece of
text (`p`, Writer's `text:p` and `text:h`, `h1` to `h6`, `li`, `para`,
SVG's `text` and `tspan`, a `span` or an `a`), one inside such an
element, as Word's `<w:r>` run in its `<w:p>`, one whose elements are all
inline formatting (`b`, `i`, `u`, `em`, `strong`, `bold`, `italic`, a
`span`, `a`, `code`, `sub`, `sup` and the like, Gnote's `size:` and
`link:` runs), as `<list-item><bold>olive oil</bold></list-item>`, or
whose runs split a sentence at a space, as `Meet ` and a linked
`Monday`. Nor does an element holding a date the app stamps in parts
take a text check.
- An element added to a list, where another element of its tag is at either
end, gets a `value_equals` for each of its attributes, best ranked first,
at most six, leaving out its selector's attributes, identifiers, times,
volatile values, view state and values standing for none, as HomeBank's
new `<ope>` gets its `amount`, `category` and `payee`; a value two or
more like siblings all hold, as Grisbi's `Cu="1"`, comes after those
that vary, as its `Pa`, `Ca`, `Dt` and `Am`. Records of attributes
alone that it nests, as a KMyMoney `<TRANSACTION>` its `<SPLITS>` of
`<SPLIT>`, get a `value_equals` of each attribute whose values vary among
the like records, its own and those under its like siblings, at most
three a record and six in all, as each split's `value` and `payee`, but
not one every split holds alike, as `price="1/1"`, nor one each holds
equal to an earlier one, as `shares` repeats `value`. Each record is
named by an identifier that the app neither generates nor numbers anew
in every record holding such a list, as KMyMoney's `S0001` in every
transaction, else by its best ranked attribute short of a coordinate or
an amount, as `[name=SPLIT][@account=A000001]`. An element whose other attributes, two
or more, a like sibling holds every one of, as a new Planner task copies
its neighbour's defaults, and any other element added whole, get a check
that it exists; of those copied, an attribute naming an element the seed
holds by an id that is no plain number, as an Umbrello attribute's
`type` its data type, is the user's choice and keeps its check. A record added to a list that a selector names, as
Tellico's `<entry id="4">` or Osmo's `<record>` by its first name, gets
a `text_equals` for each field, at most five, each by its selector among
the record's fields, as `[name=title]`, leaving out a field repeating the
record's identifier, the field its selector names it by unless it is
the only one left, as a new VYM branch's `<heading>`, a value every
like record holds in that field, as Osmo's `<group>None</group>`, noise,
a field holding ids of its own, a date the app stamps in parts, and blank
text or times; a field that lists records, as GnuCash's `<trn:splits>`,
gets its records' fields instead, each record by its own selector. An
attribute every like record holds alike, as GnuCash's `version`, is the
format's and gets no check. A record only position names also gets a
`text_contains` for each new field of three or more characters, at most
five, at the nearest ancestor a check can name, each absent from that
ancestor's text at the seed.
- Where members of a list were added or removed, a `member_count` of the
list's members of their tag, and of their kind where they share one
(`type`, `kind` or `shape`, as `[name=dia:object][@type=Flowchart - Box]`),
unless every member of the tag holds a value of its own, as Tiled's
objects a free-form `type` (`well`, `door`, `gate`), which labels each
rather than grouping them,
equal to the end's number, which differs from the seed's: at most two a
file, the shallowest lists first, after the other checks. None for a
list of one member at both ends, as a style an app adds for a run, for
members of an element a text check reads, which are runs of its text,
for an element in mixed content, or for noise.
- A decimal written as text, such as `146.83`, is suggested as a number
with `tolerance: 0.001`, unless the seed's value, read as the evaluator
reads a number (`10` and `1e1` included), is that close too. A
`value_equals` that would pass on the seed's value is not suggested.
- An element placed by its own position, holding numeric `x` and `y` as a
like sibling does, as Xournal++ places each `<text>` note on a layer, is
an item of its own, never a run of the others' text: one added whole
gets a `text_contains` of its text on the element holding the items,
which passes wherever it is placed, and that list's `member_count`.
- Noise leaves the suggestions when the file's change holds anything
else, a change only position reaches included: view state, which a tag
or attribute on the way names (the cursor, a selection, as VYM's
`<select>`, the layer, frame,
view or colour the app has current, as Pencil2D's `currentLayer`,
scrolling, zoom, the viewport, windows, splitters, a list or tree view
mirroring the document, as Umbrello's `listview`, Inkscape's `namedview`, view and
configuration settings, the printer, a save's history, edit time,
editing duration and cycles, last-saved time, the generator and
document statistics, and a preview or thumbnail the app renders, as
Xournal++'s `<preview>`), or the value of a name-like attribute or `key` on
the way, when it is one token of several words, as LibreOffice's
`config:config-item[@config:name=CursorPositionX]` inside
`[@config:name=ooo:view-settings]`, or a settings path ending in how a
panel shows (`visible`, `hidden`, `expanded`, `geometry`, `size` and the
like), as VYM's `<setting key="/treeeditor/visible">`; an identifier the
app numbers by position. An `Id` suffix alone does not show that an
attribute is generated, so relationship fields such as `accountId` are
retained; other save-generated IDs may need manual review; volatile
values, UUIDs and epoch times, binary data encoded as base64 (a PNG's
`iVBORw0KGgo`, or 256 or more base64 characters mixing cases and
digits), an id counter (`uniqueid`, `nextobjectid`), a value equal to an
id the change gave a new element where a counter or that element holds
it, as Umbrello's `lastobject` holds the new attribute's `xmi:id`, but
never a reference on an element both ends hold, as a KMyMoney split
moved to a new account, and durations and counts under a document's metadata; times the app stamps, also as a date written in
parts whose tag, or one it sits in, names when the app made, changed or
saved something, as Tellico's `<cdate>` of `<year>`, `<month>` and
`<day>` (`cdate`, `mdate`, `created`, `modified`, `saved`, `updated`,
`entered`), or written whole under such a tag, as GnuCash's
`<trn:date-entered><ts:date>2026-11-06 08:53:08 +0000`,
which no check ever reads, while a date a user enters in parts, as a
birthday, is an edit like any other; an id the app assigns, an `id`
element with `type="guid"`, as GnuCash's `<trn:id>`, and text of control
characters, as its unset options hold; `upkeep`, a change inside an
app's `slots`, as GnuCash's `book:slots`, which it adds to and fills on
reopening a book, a count an app keeps of its members, an attribute
whose key ends in `count` or an element whose tag names a count, whose
integer changed and at each end equals how many elements of one tag it,
or the element holding the text, holds there, the counter left out, as
VYM's root `branchCount`, KMyMoney's `<TRANSACTIONS count="5">` or
GnuCash's `<gnc:count-data>`, or, for a counter the change added, how
many of one tag, more than one, it holds as children, as FreeCAD's
`<ObjectDeps Count="2">`, while a count a user enters, as an item's
`<count>`, is an edit, and the `loext:tab-stop-distance` attributes
LibreOffice fills in `styles.xml` while another entry holds the edit,
and, while a change outside them is the edit, any
change in `styles.xml`, in a document's style containers or its master,
handout and notes pages, or to an attribute naming an automatic style
(`P1`, `MT1`) at both ends, as Impress after a reload wraps its master pages' fields in a new `MT1` style and
rewrites list style `L2`, and a text showing another field that changed
alike, its element beside a field naming that one's key, as
QElectroTech's `<dynamic_elmt_text>` shows a component's label in its
`<text>` beside `<info_name>label</info_name>`; and `layout`, attributes holding a list of
numbers, as Dia's `obj_bb` `6.3225,6.15;12.5775,8.15`, or a number a
name on its way calls layout (a position, point, box, corner, width,
height, side or offset, as `elem_width`), that changed in an element up
to three levels below one whose text changed, below the root's own
children, while their own element's text did not, as Dia moves and
resizes a box around its new text, or below an element whose tag names a
diagram, widget, canvas or scene while the model change is elsewhere, as
Umbrello grows a class's `classwidget` `height` when an attribute is
added; an order's `<amount value="12"/>` beside its new description is
content. Geometry that changed with
no text beside it, as a CAD sketch's, is content. However much noise
comes first, it never takes a check's place. When the change holds
nothing else, the checks stay and a note flags them: up to three in a
document, and as many as fit in the app's own state, where a view
setting may be the task.
- Whitespace an app lays out between elements is not checked, and values
that look like a time the app stamps, in ISO 8601, as C's `asctime`
writes it (`Thu Nov 5 09:20:31 2026`) or as a time of day to the
second (`05:16:21.675302540`), are left out; noise never makes its
ancestor's whole text a check.
- `guards`: checks an author may add to show the edit left the rest alone,
kept out of `task.checks`, with ids `guard-1` and on: for each suggested
`value_equals` or `text_equals` on a member of an XML list, or a
`value_equals` through a JSON record added whole, as TreeLine's new book's
`data/Author` gives
`/nodes/[format=BOOK][>data~1Title=Small Engines of Life]/data/Author`
(its like records are those of its kind, named as both ends pair them,
and it reads only the check's own field), a field on up to
two like siblings, those sharing most of the attributes its selector
names it by and its type, as a cell's `Row` or `Col` and `ValueType`,
then the nearest first, at its seed value, which the end holds
too, trying at most the 16 nearest, so a guard costs the same among
thousands of siblings; for a member named as a field, by a name-like attribute alone, as
QElectroTech's `elementInformation[@name=label]`, the like siblings of
the nearest record out that hold that field too come first, so the other
components' labels guard a component's label rather than its other
fields: the check's own field where like siblings hold different values in
it, and otherwise one that varies among them, as Planner's `work` rather
than the `type="normal"` every task shares, but not one numbering the
members in order, as MyPaint's `src`; never through a sibling only
position pairs. A guard never selects its sibling by
what it reads: a sibling its selector names by the attribute the guard
checks, or by a value that is or holds the text it reads, as Glade's
`[>object=CancelTrueTrueTrue]` for a button's `Cancel` label, is named by
another identifier, name-like attribute or child's text it holds alone
at both ends instead, as Tiled's objects by `[@id=2]` rather than the
`name` the guard reads, or Glade's button by `[>packing=TrueTrue0]`, or
else the guard reads another field, or there is none. A `text_equals` with `text_attribute`
reads its siblings the same way. A text file gets a `lines_present` of the
nearest two unchanged lines of its first new line's kind, list items with the same
marker, as Zim's other `[ ]` action items, or lines the same command
opens, as the other headings after LyX's `\begin_layout Section`, or lines
of the same keyword or `key:` in other records, as a gettext catalogue's
other `msgstr` lines rather than the edited entry's own `msgid`, or else
its nearest lines with words in them; each text both ends hold once, never
a line with no text of its own, a command such as `\end_layout`, tags
alone such as `<fonts>` or `</node>`, or a key alone such as a RedNotebook
day's `24:`, nor a line that repeats; an item placed by its own position
that an edit added, a `text_contains` of each of up to four kept items'
text, nearest first. Where members were only edited, a
`member_count` of the innermost list holding the edited element that an
edit goes through by a member with like siblings, a record rather than a
field of one (a member named by a name-like attribute alone that the
record's like siblings hold too), of the edited member's tag and kind, at
the seed's number, as Dia's boxes in their layer, MyPaint's layers in
their stack or Glade's buttons in their button box: no member of the kind
added or removed; never of runs in an element a text check reads, and
only where the end holds the same number. A guard of a coordinate comes
after those of text. At most four a file besides the count guard, which
sits outside that cap, so sibling guards never squeeze it out. They pass
on the seed, which the export allows, since one check failing there is enough.
- `notes`: why `files` is empty, or why a file's suggestions are thin. Each
note has a `code` and a `message`. For a draft with no files: `no_change`
when no file under the home changed between the two checkpoints and nor
did the application's dconf keys; `unowned_changes` when files changed but
none under the owned paths, with up to five of them in `files`, each with
its home path and role (desktop services' files last), and how many more
in `more`; `uncheckable_changes` when the application's keys in a dconf
database changed, with the database in `files`: no check reads dconf, and
the export only writes the keys as they were at the seed checkpoint, so
make the task's change one the app saves in a file; `unreadable_changes`
when a dconf database changed but REA could not read it, with the read
failure in `error` (install `dconf-cli` or set `REA_DCONF_COMMAND` when it
is missing), since whose keys changed is then unknown; and `no_document`
when no file has the document role, as when no window title shows the
file's name. A capture again with `--state-path` naming the file, or
`state_paths` on a build computer's `start_build_capture`, makes it the
app's. For a drafted file, named in `file`: `by_position` when
changes reach their element only by position, the tags no attribute names
alone in `elements`, or when only the elements' order changed;
`view_state_only` when every change is noise, the checks kept in
`pointers`; `long_text` when an element's text changed past the 2,000
characters a text check compares, the elements in `pointers`; `cut_view`
when the views hold only part of the file; `unreadable_view` when no
check can read it, as a document REA reads as binary;
`volatile_lines` when a text file gained lines holding a value the app
generates with no text before it to count them by; `generated_reference`
when an array references a newly generated record ID that cannot be checked
exactly across runs, with up to five affected `pointers`; and `read_as_text`
when a text file opens like XML, with a declaration, a DOCTYPE or an
element, but reads as text because its DOCTYPE has an internal subset or
it is not well formed, so its checks compare lines that hold attributes in
the order the app wrote them.
The suggestions are a starting point. Keep the ones that say what the user
did; drop the ones that only follow from how the app saves its file. A LibreCAD
did; drop the ones that only follow from how the app saves its file. Read
`values` for what changed and its pointers, and `refers_to` for what a number
stands for, before writing the prompt and any check of your own. A LibreCAD
capture that added four holes to a drawing rewrote it from DXF R12 to DXF 2007,
so most of its lines changed; the draft suggests counts of `SECTION`, `ENDSEC`
and `CIRCLE`, and only `CIRCLE` going from 5 to 9 is the user's change.
@@ -80,7 +502,7 @@ and `CIRCLE`, and only `CIRCLE` going from 5 to 9 is the user's change.
```json
{
"name": "add-milk",
"prompt": "Add buy milk to my to-do list in Mousepad and save it.",
"prompt": "In Mousepad, add buy milk to my to-do list and save it.",
"checks": [
{
"id": "milk",
@@ -93,31 +515,35 @@ and `CIRCLE`, and only `CIRCLE` going from 5 to 9 is the user's change.
```
`name` is a portable bundle name other than `smoke` (lowercase letters, digits
and hyphens); `prompt` is what the user asks for; `checks` holds 1 to 32
and hyphens); `prompt` is what the user asks for, naming the app, since a
solving agent's own shell cannot see the computer's files and the app's name
sends it to the screen; `checks` holds 1 to 32
checks. Each check has a `kind`, a `file` given as a path under the home such as
`Documents/todo.txt`, and an optional `id` (`check-1`, `check-2` and so on by
position otherwise). A check reads the typed view `data/get` returns for that
file, in the shapes of the state view.
| Kind | Fields | Passes when |
| --------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------ |
| `file_present` | | The file exists |
| `file_absent` | | The file does not exist |
| `lines_present` | `lines` | Every listed line is a whole line of the text view |
| `lines_absent` | `lines` | None of the listed lines is |
| `line_count` | `exact` or `contains`; `equals`, `at_least` or `at_most` | The number of lines equal to `exact`, or holding `contains`, compares so |
| `value_equals` | `pointer`, `value`; optional `tolerance` | The pointer names a value equal to `value`, or within `tolerance` of it |
| `value_absent` | `pointer` | The pointer names no value |
| `text_equals` | `pointer`, `value`; optional `normalize_whitespace` | The XML element's [whole text](#whole-text) equals `value` |
| `text_contains` | `pointer`, `value`; optional `normalize_whitespace` | The XML element's whole text holds `value` |
| `row_present` | `table`, `where` | A row of the SQLite table has every column in `where` equal |
| `row_absent` | `table`, `where` | No row does |
| `row_count` | `table`; optional `where`; `equals`, `at_least` or `at_most` | The number of rows, or of rows matching `where`, compares so |
| Kind | Fields | Passes when |
| --------------- | --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| `file_present` | | The file exists |
| `file_absent` | | The file does not exist |
| `lines_present` | `lines` | Every listed line is a whole line of the text view |
| `lines_absent` | `lines` | None of the listed lines is |
| `line_count` | `exact` or `contains`; `equals`, `at_least` or `at_most` | The number of lines equal to `exact`, or holding `contains`, compares so |
| `value_equals` | `pointer`, `value`; optional `tolerance` | The pointer names a value equal to `value`, or within `tolerance` of it |
| `value_absent` | `pointer` | The pointer names no value |
| `text_equals` | `pointer`, `value`; optional `normalize_whitespace`, `text_attribute` | The XML element's [whole text](#whole-text) equals `value` |
| `text_contains` | `pointer`, `value`; optional `normalize_whitespace`, `text_attribute` | The XML element's whole text holds `value` |
| `member_count` | `pointer`; optional `matching`; `equals`, `at_least` or `at_most` | The number of [members of the array](#counting-members), or of those `matching` names, compares so |
| `row_present` | `table`, `where` | A row of the SQLite table has every column in `where` equal |
| `row_absent` | `table`, `where` | No row does |
| `row_count` | `table`; optional `where`; `equals`, `at_least` or `at_most` | The number of rows, or of rows matching `where`, compares so |
The rules both evaluators follow:
- An absent file reads as empty: no lines, values or rows. So `lines_absent`,
`value_absent` and `row_absent` pass on it and a count is 0.
`value_absent` and `row_absent` pass on it and a count of lines or rows is
0; `member_count` fails, since its pointer names no array.
- A file that has no view (binary, over the read limit, or unreadable) fails
every check but `file_present` and `file_absent`. Line checks need a text
view, row checks a SQLite view and text checks an XML view, in a file or an
@@ -129,7 +555,9 @@ The rules both evaluators follow:
`{"groups": {"GROUP": {"KEY": "VALUE"}}}`, so a setting is
`/groups/GROUP/KEY`; XML as `{"root": {"name", "attributes", "children"}}`;
SQLite as `{"tables": {"TABLE": {"columns", "rows"}}}`; a zip archive as
`{"entries": [{"name", "format", "view", …}]}`.
`{"entries": [{"name", "format", "view", …}]}`; a gzip file, such as a
Gnumeric `.gnumeric`, as the document inside it, so its pointers are those
of the same document uncompressed.
- With `tolerance`, a non-negative number, `value` must be a number, and the
value found passes when it is a number, or a string that is a decimal
numeral such as `"5.0000000000000000"`, at most `tolerance` from `value`.
@@ -149,12 +577,15 @@ The rules both evaluators follow:
The export refuses, naming the check, a file outside the owned paths, a file
spelled with a leading slash, `.` or `..`, a pointer into a file that is text
at the seed, as the bundle ships it, or at the end checkpoint, the empty
pointer (the whole file), a value that names the captured home, or the
pointer (the whole file) except in `member_count`, a `matching` that is no
selector, a value that names the captured home, or the
capture host's name or `user@host` anywhere (which the
[export removes from the seed](desktop-application-export.md#host-name-and-user)), a
`tolerance` with a value that is not a number, an empty `text_contains`
value, or one of only whitespace with `normalize_whitespace`, and a value that
looks like a date and time, in ISO 8601 or `asctime`'s form. Other volatile
value, or one of only whitespace with `normalize_whitespace`, an empty
`text_attribute`, a count without exactly one of `equals`, `at_least` and
`at_most`, and a value that looks like a date and time, in ISO 8601 or
`asctime`'s form. Other volatile
content, such as a
counter the app bumps on every save, is for the author to leave out.
@@ -171,9 +602,31 @@ rather than by its position:
`[name=Object]`.
- `[@KEY=VALUE]` names the member whose `attributes` hold `KEY="VALUE"`, as
the XML view keeps an element's attributes.
- `[>PATH=VALUE]` names the member that holds `VALUE` at a path of one to
three `/`-separated steps inside it. `>` reads XML and JSON differently:
| Form | In an XML element | In a JSON record |
| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- |
| `[>CHILD=VALUE]` | a child element `CHILD` whose text, every text node in it with each run of whitespace collapsed to one space and none at either end, is `VALUE` | the string field `CHILD`, compared whole |
| `[>A/B=VALUE]`, up to `[>A/B/C=VALUE]` | a child `A` with a child `B` of that text | the string at `member.A.B`, compared whole |
| `[>A@ATTR=VALUE]`, `[>A/B@ATTR=VALUE]` | a child `A` (or its child `B`) whose attribute `ATTR` is `VALUE` | the field named `A@ATTR`: `@` is part of a JSON key |
Records that keep their fields as elements are named by a child's text:
Osmo's `<contact><first_name>Delphine</first_name>…` is
`[name=contact][>first_name=Delphine]`. A GtkBuilder `<child>` is named by
the id its widget carries, `[name=child][>object@id=submit_button]`, and a
TreeLine node by a field of its `data`,
`[format=BOOK][>data/Title=The Silk Roads]`. Any element on the way will
do; a path with more than three steps, or an empty one, is no selector;
and a missing step, or a value at its end that is not a string, matches
nothing.
- Conditions can follow one another, `[name=Object][@name=Hole]`, and all must
hold. They compare strings only, the selector is escaped like any pointer
segment (`~1` for `/`), and a value cannot hold `][`.
segment, so a path's `/` is `~1` inside a pointer,
`/nodes/[format=BOOK][>data~1Title=The Silk Roads]`, and a `/` in a key
cannot be a step; a value cannot hold `][`. A JSON field whose key begins
with `@` or `>` is selected through a path, `[>@type=Book]`.
A selector must name exactly one member. When several match, or none does
before the last segment, the check fails and says which selector matched what.
@@ -187,7 +640,7 @@ FreeCAD 0.21 and 1.0 alike:
```json
{
"name": "cut-hole",
"prompt": "Cut a 10 mm hole through the middle of the plate and save it.",
"prompt": "In FreeCAD, cut a 10 mm hole through the middle of the plate and save it.",
"checks": [
{
"id": "cut",
@@ -294,6 +747,51 @@ read the element's whole text instead:
and trims both ends before comparing, as XPath's `normalize-space()` does,
for an app that reflows text or a value written across lines. A no-break
space is not whitespace there.
- `text_attribute` reads text an app keeps in an attribute: the element's
text is then that attribute's values on it and its descendants, joined in
document order, and its text nodes are left out. Scribus keeps a text
frame's text as `<StoryText><ITEXT CH="Spring "/><ITEXT CH="Fair"/></StoryText>`,
one `ITEXT` per run of formatting, so the check below reads `Spring Fair`
however the runs are split. The pointer must name an element; a text node
or attribute value fails.
```json
{
"id": "headline",
"kind": "text_equals",
"file": "Documents/flyer.sla",
"pointer": "/root/children/[name=DOCUMENT]/children/[name=PAGEOBJECT][@ANNAME=Headline]",
"value": "Spring Fair",
"text_attribute": "CH"
}
```
## Counting members
`member_count` counts the members of the array its pointer names: a JSON
array, or an XML element's `children`. `matching`, a selector of one or more
conditions as [above](#pointers-and-selectors), `[>PATH=VALUE]` included,
counts only the members it matches, however many; without it every member
counts. An element's children hold its text nodes too, so give `matching`
for XML, such as `[name=entry]`. A Tellico task that adds one book to a
collection of 12:
```json
{
"id": "one-more-book",
"kind": "member_count",
"file": "Documents/books.tc",
"pointer": "/entries/[name=tellico.xml]/view/root/children/[name=collection]/children",
"matching": "[name=entry]",
"equals": 13
}
```
It takes exactly one of `equals`, `at_least` and `at_most`. The empty
pointer `""` names the whole file, for a JSON file whose top level is an
array. A pointer that names no array, an absent file's included, fails and
says what it found there. Like the other counts, it is undecided on a view
that may hold only part of the array.
## Validation and export
@@ -322,7 +820,10 @@ The bundle then holds, besides the app and `tasks/smoke.json`:
The verifier finds the app among the computer's child environments, calls its
`data/get` under the run's grant of the computer's control token, and reads
the `state` data part. It raises when the app cannot be reached, so the run
the `state` data part. It reads again until the app's files settle, as
[grading once the app has saved](desktop-application-export.md#grading-once-the-app-has-saved)
describes, and each result's `settled` says whether they did, and `read_cut`
whether the bound cut a read still running. It raises when the app cannot be reached, so the run
fails rather than scoring the agent. The README lists the task, its prompt, its
checks and the recipe below.
@@ -339,7 +840,10 @@ done
```
The agent defaults to Claude Code and the model is the caller's choice (Claude
Sonnet 5.5 is a reasonable reference). A run reported as `scored below 1`
Sonnet 5.5 is a reasonable reference). The agent calls a model endpoint, and
agentenv refuses the run without one: set `LITELLM_BASE_URL` and
`LITELLM_API_KEY` where the runs start, or `base_url` and `api_key` under
`[model]` in `.agentenv/config.toml`. A run reported as `scored below 1`
failed the checks and counts as a miss; one reported as `failed` did not finish,
as when the computer or the app could not be reached, and is run again rather
than counted. Each run's instance keeps the verifier's results per check under
+163 -26
View File
@@ -18,13 +18,66 @@ app, exporting its bundle and witnessing the task on such a computer are in
skill for doing all of it from a request is
[desktop builds](https://github.com/morluto/rea/blob/main/.agents/skills/reverse-engineer-anything/references/desktop-build.md).
## Set up a build host
On a Linux host with Node.js and Docker, from a REA
[checkout](getting-started/installation.md#run-rea-from-a-checkout):
```bash
rea setup --client claude_code --desktop-build --install-agentenv
rea doctor --provider desktop_build --client claude_code
```
Setup shows its plan and asks before it changes anything; `--dry-run` only
prints it and `--yes` approves it. It packs REA's runtime archive into
`~/.cache/rea/build-computer/rea-<version>.tar.xz` (under `$XDG_CACHE_HOME`
when set, `~/Library/Caches` on macOS), and packs again once REA's version
changes; an archive `REA_BUILD_COMPUTER_REA_ARCHIVE` already names is
recorded instead. It records `REA_AGENT_ENV_COMMAND`, `REA_DOCKER_COMMAND` and
`REA_BUILD_COMPUTER_REA_ARCHIVE` as absolute paths in that client's REA
registration, keeping a value the registration already has other than an
archive setup packed for an earlier REA version, and refreshes the skill.
`--install-agentenv` runs `uv tool install agentenv-framework==0.9.1464`
when `uv` is on `PATH`, and otherwise prints the command. Setup never
installs Docker or Node.js and never runs `sudo`. Restart the client
afterwards.
Doctor is read-only and checks, in order: a Linux amd64 or arm64 host,
Node.js, procps `ps`, the Docker CLI, a Docker daemon reachable without
`sudo`, 20 GB free where Docker keeps images, agentenv-framework 0.9.1464,
the runtime archive of this REA version, the build settings in the
registration or the environment, and the skill. Each failure names its fix.
It also reports, without counting them against `healthy`, whether a model
endpoint for solver runs is configured and which agentenv containers
earlier builds left. Pass `--json` for the full report.
When a setting is unset where the server starts, REA uses `agent-env` and
`docker` on `PATH` and the archive setup packed for this REA version. The
rest of this page is the same setup by hand.
## Requirements
- Docker, and an agentenv-framework install whose `agent-env` program is named
by the absolute `REA_AGENT_ENV_COMMAND`. Bundles target agentenv
0.9.1431. REA runs its helper, `bridge/agentenv/computer.py`, with that
runner's Python: the interpreter on the program's `#!` line, or the
`python3` beside it in its virtual environment.
- A Linux host on amd64 or arm64 with about 20 GB of free disk for the
images agentenv builds and pulls. amd64 and arm64 hosts both build
natively; a host builds only its own architecture.
- Node.js at the version in `.nvmrc`, installed with
[nvm](https://github.com/nvm-sh/nvm) or from
[nodejs.org](https://nodejs.org/en/download), and REA
[run from a checkout](getting-started/installation.md#run-rea-from-a-checkout).
- [Docker Engine](https://docs.docker.com/engine/install/) and its
[post-install steps](https://docs.docker.com/engine/install/linux-postinstall/):
add yourself to the `docker` group, then log in again.
- agentenv-framework 0.9.1464, the version bundles target. Install
[uv](https://docs.astral.sh/uv/getting-started/installation/) first, then
run `uv tool install agentenv-framework==0.9.1464`. Set
`REA_AGENT_ENV_COMMAND` to the absolute path of the resulting `agent-env`
program, normally `$HOME/.local/bin/agent-env`; `command -v agent-env`
shows the path when its install directory is on your `PATH`. Installing it
with pip into a virtual environment instead needs `python3.12-venv` on
stock Ubuntu. REA runs its
helper, `bridge/agentenv/computer.py`, with that runner's Python: the
interpreter on the program's `#!` line, or the `python3` beside it in its
virtual environment.
- `REA_DOCKER_COMMAND`, the absolute path of the Docker CLI, lets REA remove a
computer whose agentenv teardown was not confirmed. Without it, REA names the
command to run instead.
@@ -34,20 +87,83 @@ skill for doing all of it from a request is
checkout, `npm run pack:build-computer-runtime -- /path/to/rea-prod.tar.xz`
writes one: `npm pack`, its package folder as
`rea-prod` with the lockfile, `npm ci --omit=dev --omit=optional`, then
`rea-prod` as `.tar.xz`.
`rea-prod` as `.tar.xz`. The archive is a copy of the checkout: pack it
again after `git pull` and a rebuild.
Set these where the MCP server starts; a shell export does not reach a server
that is already running.
## Claude Code
Without `--desktop-build`, `rea setup --client claude_code` registers REA
without these variables. Either
export them in the shell that starts `claude`, which starts REA's server with
its environment:
```bash
export REA_AGENT_ENV_COMMAND="$HOME/.local/bin/agent-env"
export REA_DOCKER_COMMAND="$(command -v docker)"
export REA_BUILD_COMPUTER_REA_ARCHIVE="$HOME/rea-runtime/rea-prod.tar.xz"
claude
```
or set them, as absolute paths, in the `env` of the `mcpServers.rea` entry
setup wrote, such as in `~/.claude.json`:
```json
{
"mcpServers": {
"rea": {
"command": "/absolute/path/to/node",
"args": ["/absolute/path/to/rea/scripts/rea.mjs", "mcp"],
"env": {
"REA_AGENT_ENV_COMMAND": "/home/ada/.local/bin/agent-env",
"REA_DOCKER_COMMAND": "/usr/bin/docker",
"REA_BUILD_COMPUTER_REA_ARCHIVE": "/home/ada/rea-runtime/rea-prod.tar.xz"
}
}
}
}
```
Solver runs are `agent-env run` commands the agent runs in its shell, and
agentenv refuses them without a model endpoint: export `LITELLM_BASE_URL` and
`LITELLM_API_KEY` in the shell that starts `claude`, whose Bash tool inherits
them, or set `base_url` and `api_key` under `[model]` in
`.agentenv/config.toml`.
Claude Code asks before each MCP tool call its permission settings do not
allow, and a build makes dozens of `act_on_build_computer` calls. You can
allow REA's tools in those settings' `permissions.allow` list:
`mcp__rea__act_on_build_computer` allows that tool, and `mcp__rea` allows all
of REA's.
A headless run, `claude -p`, ends when the skill asks its upfront questions,
and refuses the tool calls its permission settings do not allow. Put the
answers in the request: the install source when the app is not in the Ubuntu
archive, a synthetic seed or the file to start from, whether to review the
task before solver runs, and the solver runs' count, model and budget, or
none:
```bash
claude -p 'Build me a Gnote environment where the agent adds olive oil to the
shopping list note. Make a synthetic note. Then make 2 solver runs with
<model>, at most $4 in all, without a review first.'
```
## Start a computer
From a request, REA renders a bundle in a private temporary folder: a computer
app on the `ubuntu-24.04` base with the `reference` driver that installs the
app, opens it on demand with `gtk-launch <desktop entry>` from the computer
user's home, so its open and save dialogs start there rather than in the
framework's folder for the app, and keeps no seed and no data hooks. The app is not open when the computer starts: agentenv lists it
in the desktop's Applications menu under Other by the environment's name, such
as `mousepad`, and that entry launches it through the app's server.
framework's folder for the app, and keeps no seed and no data hooks. The app is not open when the computer starts:
`start_build_capture` opens it under REA's capture. When no capture is under
way, open it from the desktop's Applications menu, where agentenv lists it
under Other by the environment's name, such as `mousepad`; that entry launches
it through the app's server. The name is the desktop entry's last part when it
is reverse-DNS (`com.github.xournalpp.xournalpp` gives `xournalpp`), or else
the whole entry without a trailing version (`glabels-3.0` gives `glabels`).
When the app is Electron, set `electron` to true. The install rewrites that
desktop entry's command with the same policy an export uses: `--no-sandbox`
@@ -71,16 +187,28 @@ Applications menu entry can open the app.
| `kind` | Installs |
| ---------------- | ---------------------------------------------------------------------------------------------------------- |
| `archive` | `package` from the Ubuntu 24.04 archive, on amd64 and arm64 |
| `archive` | `package` from the Ubuntu 24.04 archive, on amd64 and arm64, with its optional `extra_packages` beside it |
| `apt_repository` | `package` from the repository at `uri` with `suite` and `components`, trusting the key file `key_file` |
| `package_file` | The `.deb` at `url`, checked against `sha256`, for one `architecture`, after its apt `dependencies` are in |
Build steps run with the network off, so a `.deb`'s dependencies must be
listed. The bundle adds REA in a build-only layer: Node.js
listed. `extra_packages` names up to 16 more archive packages, by the same
name rules as `package`, for a runtime piece the app needs that its package
does not install: apt here skips Recommends, so MyPaint 2.0.1 exits at launch
without `librsvg2-common`, GTK's SVG icon loader, and Freeplane 1.7.10 needs
`openjdk-17-jre`, since its launcher refuses noble's default Java 21. The
export installs them beside the app too, as it does a `.deb`'s
`dependencies` when apt offers the `.deb`'s package; see
[build and witness](desktop-build-witness.md).
The bundle adds REA in a build-only layer: Node.js
24.22.1, downloaded per architecture and checked against its release checksum,
and REA from `REA_BUILD_COMPUTER_REA_ARCHIVE`, both unpacked into `/opt/rea` by
a root build step, with `node` and `rea` on `PATH`. An exported bundle carries
none of it.
a root build step, with `node` and `rea` on `PATH`. It also installs
`libgtk-3-bin`, for `gtk-launch`, and `dconf-cli`, so the capture reads the
app's settings in dconf, such as GnuCash's "Show tips at startup", and the
seed keeps them. An exported bundle carries none of it but `dconf-cli`, which
it installs when it loads the app's dconf keys.
From a bundle folder, such as one `export-desktop-application` wrote, REA
starts that bundle's `tasks/smoke.json` as it is:
@@ -96,6 +224,10 @@ in the folder and its files stay as they were shared.
REA runs the deploy with `run_bundle(keep=True, emulate=False)` on the local
sandbox provider, so only the host's own architecture is built. The first start
of a bundle builds its image and can take minutes; later starts reuse it.
agentenv makes a start wait while another agentenv run on this host writes its
bundle's ids, so starts at the same time wait for each other, several minutes
when a few run together; the progress line then says it is waiting for another
agent-env run to finish writing this bundle's ids.
While it waits, REA sends an MCP progress notification every five seconds with
agentenv's latest line, so a client that resets its request timeout on
progress keeps waiting. REA then waits until the computer's readiness checks
@@ -105,9 +237,12 @@ while it is one colour throughout. The retries share 10 s, each given only
what is left of it, and when that runs out REA returns the latest frame;
progress notifications continue meanwhile. Given `screenshot` with a
`region`, `format` or `quality`, REA then takes one with them, a `region`
cropping that frame. The result holds
cropping that frame rather than capturing the screen again. The result holds
`computer_id`, agentenv's `sandbox_id`, the environment name or bundle folder,
and the screenshot's frame as structured content beside its image.
`extra_packages`, what the request named beside the app for the export to
install too (an archive install's `extra_packages` or a `.deb`'s
`dependencies`, empty otherwise), and the screenshot's frame as structured
content beside its image.
A failed start returns the last 16 KiB of the helper's stderr, where a failing
build prints its error, and its exit status; a cancelled one stops the helper,
@@ -121,16 +256,16 @@ progress and waits for them before closing every computer.
`act_on_build_computer` takes `computer_id`, an `action` and the driver's own
arguments for `computer_<action>`, which REA passes through:
| `action` | Arguments |
| ------------ | --------------------------------------------------------------- |
| `screenshot` | `region`, `format` (`png` or `jpeg`), `quality` |
| `click` | `x`, `y`, `button`, `count` (2 double-clicks), `modifiers` |
| `drag` | `path` of `[x, y]` points, `button`, `duration_ms`, `modifiers` |
| `scroll` | `direction`, `x`, `y`, `amount`, `modifiers` |
| `type` | `text`, where `\n` presses Enter and `\t` Tab |
| `key` | `keys`, one chord pressed in order, and `repeat` |
| `wait` | `ms` |
| `reset` | `screenshot` |
| `action` | Arguments |
| ------------ | ----------------------------------------------------------------------- |
| `screenshot` | `region`, `format` (`png` or `jpeg`), `quality` |
| `click` | `x`, `y`, `button`, `count` (2 double-clicks), `modifiers` |
| `drag` | `path` of 2 to 50 `[x, y]` points, `button`, `duration_ms`, `modifiers` |
| `scroll` | `direction`, `x`, `y`, `amount`, `modifiers` |
| `type` | `text`, where `\n` presses Enter and `\t` Tab |
| `key` | `keys`, one chord pressed in order, and `repeat` |
| `wait` | `ms` |
| `reset` | `screenshot` |
`reset` is not a driver tool: REA calls the app's `data/reset`, which restores
the bundle's seed and relaunches the app, then waits until the computer's
@@ -154,7 +289,9 @@ The result carries the driver's content unchanged, its text and images, after
REA's own JSON: `action_index` and the driver's structured result. A refusal,
such as a stale frame, is an error carrying the computer's message. A response
larger than the MCP budget is refused with how to ask for a smaller image: a
`region`, or `jpeg` with a lower `quality`. That error keeps REA's own result,
`region`, or `jpeg` with a lower `quality`. A screenshot with `region` does not
capture the screen again; it crops the latest frame, so take a full
screenshot, or a `wait` with `screenshot: true`, first. That error keeps REA's own result,
`computer_id` included, as `details.result`, since the action or start has
happened.
+137 -27
View File
@@ -10,7 +10,7 @@ grades the witness with the same checks the exported verifier runs.
| Tool | What it does |
| -------------------------- | ------------------------------------------------------------------------------------------- |
| `start_build_capture` | Downloads the package lists as the computer's user and launches the app under REA's capture |
| `mark_build_checkpoint` | Takes a named checkpoint and returns the capture's acknowledgement with its counts |
| `mark_build_checkpoint` | Takes a named checkpoint and returns the capture's counts and the files that changed |
| `stop_build_capture` | Stops the capture and returns its checkpoints and the task draft between `seed` and `end` |
| `export_build_environment` | Exports the bundle with the agent's task inside the computer and copies it to a folder here |
| `check_build_task` | Grades a task against the app's live state; with a `stage`, files the check in the witness |
@@ -41,6 +41,34 @@ See [desktop builds](https://github.com/morluto/rea/blob/main/.agents/skills/rev
from a `.deb` file, the build layer keeps that file at
`/opt/rea/package.deb` and the capture records it with `--package-file`. Do not open the app from
the menu first: the capture refuses an app whose window is already open.
When the capture ends before the window opens, REA reads its output. An app
that exits at launch, such as one missing a runtime, is reported with its
program, exit code, run time and the last lines of its stderr, at most 8
lines and 800 characters of the last 8 KiB the capture keeps, and
`details.diagnostics` keeps the capture's record of the session. A capture
that failed, such as one refusing to start, gives its own message and
remediation, with the whole failure in `details.diagnostics.command_failure`
and, when its cleanup is incomplete, the run tokens and paths it left in
`details.resources`. A checkpoint or stop that finds the capture ended
reads its output the same way.
`state_paths` names files or folders in the computer's home that hold the
app's state, relative to the home, after `~/` or absolute under it, at
most 16; each becomes a `--state-path` of the capture, so it is retained
from the start and its files count as the app's even before they exist.
REA counts a file as a document only when an app window's title shows its
name or `~/` path, so name the file the app will save when its title shows
something else, as MuseScore's shows a score's title: a file outside
hidden folders, other than a lock such as LibreOffice's `.~lock.<name>#`,
becomes a document, which the bundle owns, seeds and opens
at launch, and one under a hidden folder such as `~/.config/MuseScore` the
app's own state, also when that folder is a link elsewhere in the home. A
path with `..`, or naming the home itself, is refused before the computer
is asked; the computer refuses an absolute path outside its home, one in
`~/.rea-build`, and one a link leads out of the home or into
`~/.rea-build`, resolving a path that does not exist yet through its
nearest existing folder, and starts nothing.
3. Make the seed through the app with `act_on_build_computer`, saving it
where the user keeps such files, such as `~/Documents`, then
`mark_build_checkpoint` `seed`.
@@ -48,37 +76,96 @@ See [desktop builds](https://github.com/morluto/rea/blob/main/.agents/skills/rev
`mark_build_checkpoint` `end`.
5. `stop_build_capture`. The app is closed and the capture finishes. The
result lists the checkpoints with their counts, the package and the
sources the capture found, its limitations and the draft: each file that
changed between `seed` and `end` with its net change, and suggested
checks with a placeholder prompt.
6. Write the task: its name, the prompt in the user's own words, and checks
that hold after the change and not on the seed.
sources the capture found, its limitations and the draft: each file under
the paths the export owns that changed between `seed` and `end`, with its
net change and, for XML files, archives, JSON and key files, its `values`,
the values the change added, changed and removed with what each was and
became, at the pointer a check names it by; suggested checks with a
placeholder prompt; and `guards`, optional checks that the rest kept its
seed values: like siblings' fields, each line kept beside new text, and
the count of a list whose members were only edited. The draft's
[task section](desktop-application-tasks.md#describe-the-change) describes
each. `notes`, each with a `code` and a `message`, say why a draft has no
files: `no_change` when no file under the home changed between them and
nor did the app's dconf keys; `unowned_changes` when files changed but
none under the owned paths, listing up to five in `files` with their
roles, desktop files last, and counting the rest in `more`;
`uncheckable_changes` when the app's keys in dconf were read and changed,
listing the database in `files`, since no check reads dconf (a version
the capture kept no copy of, as it keeps none of the database at the
start, is `unreadable_changes`, not an empty key list);
`unreadable_changes` when a dconf database changed but REA could not read
it, such as without `dconf-cli` or when a present version's bytes were
not retained, with the read `error`, so whose keys changed is unknown;
and `no_document` when no file has the document role.
`unowned_changes` and `no_document` point at `state_paths`. They also say,
for a drafted `file`, why its suggestions are thin: `by_position`,
`view_state_only`, `long_text`, `cut_view`, `unreadable_view`,
`volatile_lines`, `generated_reference` or `read_as_text`.
6. Write the task: its name, the prompt in the user's own words naming the
app (a solving agent's own shell cannot see the computer's files, and the
export's limitations say when a prompt names neither the app's title,
environment nor package), and checks
that hold after the change and not on the seed, from the suggestions,
`values` and any `guards` worth keeping.
7. `export_build_environment` with the task and a new or empty `directory`.
The export runs inside the computer with `--seed-checkpoint seed
--end-checkpoint end`, so it seeds what was saved at `seed`, scrubs the
computer's host name and user from it, and refuses a task whose checks
all pass on the seed. A task larger than 96 KiB as REA passes it to the
computer is refused before anything runs. It also passes `--synthetic-seed`,
since the agent made the seed for the task, so the README does not call it
the user's real data. When the seed holds exactly one document and the
app's desktop entry takes files, the bundle's app opens that document at
launch. A file moved to the desktop Trash is not seeded, and the export's
limitations name what the Trash held at `seed`. For a
all pass on the seed. It also passes `--synthetic-seed`, since the agent
made the seed for the task, so the README does not call it the user's real
data. When the seed holds exactly one document and the app's desktop entry
takes files, the bundle's app opens that document at launch. A file moved
to the desktop Trash is not seeded, and the export's limitations name what
the Trash held at `seed`. The limitations and the README also name the
folders where files changed during the capture that the bundle neither
owns nor seeds, such as settings that keep a first-run wizard away, up to
eight collapsed to their top folder, such as `~/.config/MuseScore`, and a
count of the rest; capture again with them in `state_paths` to own them.
Lock files the app holds while it runs, such as LibreOffice's profile
`.lock` and its document lock `.~lock.<name>#`, GnuCash's
`<book>.LCK` or Grisbi's `.<file>.lock` beside its file, are left out of
the seed, since a copied one can keep the app from starting or saving. The
limitations and README list them after "Left out of the seed". A project's
`Cargo.lock` or `yarn.lock`, a document or a path in `state_paths`, and app
logs that are not locks are seeded. The limitations name seeded
WebKit or Chromium storage and caches too, which the app keeps for its
own running. When the application held files open in a folder whose
starting content the capture did not retain, a limitation names the
folder and the seed files in it. For a
`.deb` app that no apt source the capture found offers, the export takes
the request's URL with `--package-url`; one apt offers installs from apt. REA lists the bundle's files with their sizes
and SHA-256 in the computer, into a file beside the bundle that it reads
through `data/get`, since a large bundle's list outgrows a command's
output; it then brings the files back through the driver's
`data/get` in answers of at most 8 MiB, and checks and writes each answer
into the folder before asking for the next, so one answer at a time is
held; a failure leaves no partial folder.
the request's URL with `--package-url`; one apt offers installs from apt.
Either way the request's `dependencies` reach the export as
`--extra-package`, as an archive request's `extra_packages` do, so a
runtime piece the agent named, such as MyPaint's `librsvg2-common`, is
installed beside the app; the limitations and the README list them,
except the app itself and dependencies the bundle already names for a
`.deb` it installs from the file. REA lists the bundle's files
with their sizes and SHA-256 in the computer, into a file beside the
bundle that it reads through `data/get`, since a large bundle's list
outgrows a command's output; it then brings the files back through the
driver's `data/get` in answers of at most 8 MiB, and checks and writes
each answer into the folder before asking for the next, so one answer at
a time is held; a failure leaves no partial folder.
8. `close_build_computer`.
A checkpoint name is lowercase letters, digits, dot, dash and underscore; the
capture's own `baseline`, `stop`, `time-limit` and `exit` are refused, and so
is a name already taken. The acknowledgement comes from the capture after it
has walked the home and retained what changed: `entries` walked, `changes`
since the checkpoint before, `retained_files` and `retained_bytes`.
since the checkpoint before, `retained_files` and `retained_bytes`, and up to
ten `changed_files`, home-relative, with `more_changed_files` counting the
rest. Folders are left out. Files an app window's title has named so far
come first, as a document saved and no longer held open is in Gnumeric, LyX
or Tiled; then files named themselves in `state_paths`; then those the app
holds open, those under a selected folder and those in its state
directories; then the rest; and caches and WebKit, Chromium or QtWebEngine
storage last, even under a selected folder such as `.config/libreoffice`
with its icon cache, each by path. So a save's document leads the list.
When the computer's REA is older than these lists,
as when `REA_BUILD_COMPUTER_REA_ARCHIVE` still names an earlier build, the
checkpoint is still taken and both are `null`: which files changed is
unknown. Pack the current REA into the archive to get them back.
Each step can be asked again after its answer was lost:
@@ -102,7 +189,9 @@ computer's control token. REA sends each command through agentenv's
`computer-exec/v1` route with that token, which stays in REA, and reads larger
outputs, such as the draft, the export's Evidence and the bundle's file
list, from files under `~/.rea-build` through `data/get`, since a command's
output is capped at 1 MiB.
output is capped at 1 MiB. In a command's Evidence or failure read this way,
as in its own output, REA replaces the token in every string, after checking
the Evidence's digest; the bundle's files arrive as they are.
Calls on one computer run one at a time, in the order REA receives them:
an action, a capture step, a check or a close waits until the call before
@@ -116,7 +205,11 @@ cancels the call in progress on it and refuses the calls still waiting.
Start a fresh computer from the exported folder with `start_build_computer`
and `{"kind": "bundle", "path": ...}`; agentenv boots the app with the seed,
on the seed's document when the export opens one.
on the seed's document when the export opens one. When the computer never
gets ready and the bundle's seed holds lock files, the start's error names
them: delete them from the bundle, or export again, which leaves them out.
A bundle records no state directories, so the error names only files by a
profile lock's name and LibreOffice's document locks.
Then, with the task exactly as exported:
| `stage` | Before it | Its checks must |
@@ -129,13 +222,29 @@ Then, with the task exactly as exported:
`check_build_task` reads the app's `data/get`, takes the views it returns
beside the files and evaluates each check with REA's evaluator, the one the
export validates tasks with and the exported verifier mirrors, one result per
check. Without `stage` it only grades. The `seed` stage begins a recording
check. Once the files settle it runs the task's
[readers](desktop-application-tasks.md#readers) in the computer through
`computer-exec/v1`, as the verifier does, and a check through a reader reads
that reader's view. A task of [screen judges](desktop-application-tasks.md#screen-judges)
reads no files: REA takes a screenshot and runs the bundle's own judge on it
with the agentenv runner's Python and model endpoint. Like the verifier, it grades only once the app's files settle, since an
app such as Gnote saves a few seconds after the last key. It reads `data/get`
every 0.5 s and grades once every file's bytes have held for 3 s, counted
from the read that returned them. 15 s after the first read began, it grades
the last completed read: no read starts then, and one still running is cut.
It sends progress notifications while it waits. The result's `settled` says
whether the files settled, and `read_cut` whether the bound cut a read; each
stage in the record keeps both. Every check therefore costs at least 3 s,
and a save that lands more than 3 s after the first read returns is still
missed; see
[grading once the app has saved](desktop-application-export.md#grading-once-the-app-has-saved).
Without `stage` it only grades. The `seed` stage begins a recording
of the display under REA's own request id, one per computer; a seed check
that fails after it, such as on a failed read of the app's state or a lost
reply to the recording's start, can be asked again, and asks for the
recording under the same id, which the computer answers with the recording
it already began. The stages come in order. The edit and the near miss each
need an applied click, drag, scroll, type or key since the stage before, with
need an applied click, drag, scroll, type, typed secret or key since the stage before, with
no reset after the last of them, since a reset puts the seed back rather than
changing the app; `after_reset` needs the reset as the last change, and a
reset that leaves any check unlike on the seed fails the witness, its
@@ -171,13 +280,14 @@ A stage whose checks do not show what it must ends the witness, and so does
- `recording/NNNN.mp4`, the recording's segments;
- `witness.json`, REA Evidence (`rea.desktop-build-witness`) holding the
verdict, the stage that failed if one did, the task's name and SHA-256,
each stage's results with how many logged actions came before it, the
each stage's results with how many logged actions came before it and
whether the app's files had settled (`settled`), the
computer's [action log](desktop-build-computer.md#act) as it keeps it, each
action with its arguments, timing and outcome, with `actions_dropped`
counting the earliest actions it no longer keeps, and the recording's
segments with their sizes and SHA-256. The record's limitations say when
the log dropped actions or cut arguments, which each entry names in
`truncated_arguments`.
`truncated_arguments`, and which stages graded files that had not settled.
The stages' rules read the log's count of actions and the last applied
action of each kind, which it keeps for the whole session, so they hold
+2 -1
View File
@@ -181,7 +181,8 @@ When choosing the manual path, leave the automatic main release PR unmerged.
Select the application commit from main, create the frozen branch, and prepare
its own release PR using the steps below. Merging the main release PR starts
automatic publication instead. Close the superseded main PR after the manual
release has published and its metadata has been synchronized back to main.
release has published, before merging the metadata synchronization PR back
to main.
`release/VERSION` also sets the expected version for the workflow. Use an exact
SemVer such as `release/6.1.0` or `release/6.1.0-rc.1`, without build metadata.
+16 -10
View File
@@ -602,6 +602,12 @@ For partial Evidence delivery, verify that same-session readback preserves
identity and provenance without rerunning the provider. Include a no-writer
control that keeps completed Evidence inline and preserves the original failure.
For a seekable file with a known extent, distinguish a provably impossible wire
extent from an independent representation limit. Pair the malformed declaration
with a structurally possible over-limit control. A count-only truncated fixture
does not establish capacity behavior. This does not require decoding an opaque
compressed payload merely to apply its declared expansion limit.
When producer order is unspecified, synchronize fixtures on the observed request
or completion event. A filename, generated key, or fixed delay does not prove
which item completed before cancellation. Preserve real producer ordering and
@@ -702,16 +708,16 @@ the affected owners and applicable scenarios below. Include temporary snapshots
and one-shot commands. Use public CLI/MCP workflows where practical and a
controlled production seam for interleavings that cannot be reproduced reliably.
| Scenario | Assertion and control |
| --------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Target admitted; startup still pending | Status preserves the readiness distinction and observed startup activity; readiness requires the provider's documented proof. |
| First handshake is late, absent, invalid, or recovered during close | Initial and recovery paths retain the same authenticated identity facts. Foreign run/token controls cannot authorize cleanup; authenticated idle/native work survives the unauthenticated listener deadline. |
| Launch returns an error with a valid process handle | Cover already-exited and still-live owned processes. Verify observed exit separately from creation; failed termination or unavailable identity remains unresolved. |
| Cancellation arrives after workload exit, during result reads or temporary-root removal | Return typed cancellation with available partial observations and actual cleanup status. The non-aborted control succeeds; existing primary/cleanup failures keep their precedence. |
| Children have mixed health or cleanup outcomes | Missing peer health does not erase an observed failure or activity. Idle plus unknown stays unknown. Retry a failed child without closing a successful peer again, including after a close-option change. |
| Cleanup fails after success or primary failure | Public output retains the completed observation or primary diagnostic, remaining resources, and owner recovery action. Restore the denied resource and verify the owning cleanup retry. |
| Cleanup owners recover after an error was returned | Retain the original child and aggregate errors and project them after each owner releases. A successful peer stays released; the aggregate remains incomplete until all owners release. Preserve the first cause even when rejection is `undefined`. |
| Target exits without an acknowledgement, or transport disappears while it stays alive | Positive owned exit proof resolves target lifetime; other resources still need cleanup. Lost transport alone does not prove exit. Verify unrelated/attached targets survive and same-connection recovery works when supported. |
| Scenario | Assertion and control |
| --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Target admitted; startup still pending | Status preserves the readiness distinction and observed startup activity; readiness requires the provider's documented proof. |
| First handshake is late, absent, invalid, or recovered during close | Initial and recovery paths retain the same authenticated identity facts. Foreign run/token controls cannot authorize cleanup; authenticated idle/native work survives the unauthenticated listener deadline. |
| Launch returns an error with a valid process handle | Cover already-exited and still-live owned processes. Verify observed exit separately from creation; failed termination or unavailable identity remains unresolved. |
| Cancellation arrives after workload exit, during result reads or temporary-root removal | Before the documented commit cutoff, return typed cancellation with available partial observations and actual cleanup status. After commit, assert the owning publication outcome and receipt. The non-aborted control succeeds; existing primary/cleanup failures keep their precedence. |
| Children have mixed health or cleanup outcomes | Missing peer health does not erase an observed failure or activity. Idle plus unknown stays unknown. Retry a failed child without closing a successful peer again, including after a close-option change. |
| Cleanup fails after success or primary failure | Public output retains the completed observation or primary diagnostic, remaining resources, and owner recovery action. Restore the denied resource and verify the owning cleanup retry. |
| Cleanup owners recover after an error was returned | Retain the original child and aggregate errors and project them after each owner releases. A successful peer stays released; the aggregate remains incomplete until all owners release. Preserve the first cause even when rejection is `undefined`. |
| Target exits without an acknowledgement, or transport disappears while it stays alive | Positive owned exit proof resolves target lifetime; other resources still need cleanup. Lost transport alone does not prove exit. Verify unrelated/attached targets survive and same-connection recovery works when supported. |
Shared process-supervision controls separate leader exit from output closure.
Cover output during held or failed cleanup, bounded retention and drain timeout,
+22 -35
View File
@@ -60,23 +60,11 @@ or ordinary script path when available. Identify the specific gap and what a
new or extended contract would add; upstream capability alone does not require
a new tool or equal support from every provider.
Exercise the task through REA as a whole and compare relevant provider behavior
with an independent artifact or format observation where possible. Use the
caller's selected target and authority. Record the provider version, target and
observed coverage, and distinguish an unsupported operation from an empty
result or an untested path.
Include the boundary cases that could change the answer: provider labels versus
source facts, addresses versus file locations, partial results, and a useful
recovery after failure or session close when those apply to the task. Check that
composed results keep each observation's identity, limitations and source
association. Existing real-provider lanes and focused tests establish their
selected scenarios; they do not by themselves establish a different workflow or
provider equivalence. If a provider cannot be exercised, report that limitation
and continue with the available evidence. Measure agent tool selection only with
an actual agent evaluation; a scripted tool sequence does not establish it. Use
[testing guidance](testing.md#provider-backed-workflow-verification) to select
the cases that establish the proposed contract.
Use the caller's selected target and authority. Follow
[provider-backed workflow verification](testing.md#provider-backed-workflow-verification)
for independent observations, boundary controls and reporting unavailable
provider coverage. A scripted tool sequence does not establish agent selection;
that claim requires an actual agent evaluation.
## Audit existing tools
@@ -94,14 +82,10 @@ identity, session lifetime and available alternatives. Matching text between
two renderers does not establish that their shared advice is correct or that an
agent selected the workflow.
Exercise the selected public workflows, including the steps before and after a
tool call. Check task selection, input choices, returned facts and their source,
partial or unsupported outcomes, and applicable session and recovery behavior.
Compare native provider output and an independent artifact observation where
available. Inspect existing tests and real-provider lanes for the scenario they
actually cover; a passing test does not establish a different task or host.
Use [workflow verification](testing.md#provider-backed-workflow-verification)
for counterexamples and lifecycle controls relevant to the audit.
Exercise each selected workflow before and after the tool call. Use
[workflow verification](testing.md#provider-backed-workflow-verification) to
check returned facts, partial outcomes, recovery and the scope of existing
provider evidence.
Report working routes as well as findings. Separate a reproduced contract bug,
an intentional limitation, a design opportunity and an unverified hypothesis;
@@ -182,7 +166,7 @@ does not establish another instance.
whether applicable static relationships could have been missed by discovery;
missing discovery is unknown. Preserve paths supported by observed edges,
and qualify negative and shortest-path claims by discovery scope. Missing
relationship coverage remains `unknown`.
relationship coverage remains `unknown`. Computed candidates and unestablished incoming targets qualify directional discovery; they do not by themselves mean that recorded edges were omitted.
- Declare process, filesystem, network, UI, and mutation effects truthfully;
enforce the requested target and lifecycle.
- Add limits only for real format, protocol, authority, or measured resource
@@ -348,13 +332,15 @@ stages that never ran.
and resource release separate. A valid process handle, successful launcher,
or selected target establishes only its own fact. Publish available identity
and exit observations even when launch fails; retain unknown ownership.
- Process exit does not establish output closure. The shared process supervisor
retains at most 64 KiB of additional diagnostics from owned stop entry,
including pending cleanup and retries, and drains for up to one second after
verified stop. It marks output incomplete when closure cannot be
observed and releases owned event-loop references without changing the proven
process-cleanup outcome. Failed process cleanup retains capture for retry;
borrowed processes and streams retain their own lifetime and reference state.
- Process exit does not establish output closure. The
[shared supervisor](https://github.com/morluto/rea/blob/main/src/process/ProviderProcess.ts)
owns diagnostic retention and bounded draining through cleanup and retries.
Report incomplete output separately from process cleanup. After verified stop
and bounded draining, release owned event-loop references even if output closure
stays unconfirmed. Keep the output capture owned for retry while process cleanup
is unresolved. Borrowed processes and streams retain their own lifetime and
reference state; select the matching
[supervision controls](testing.md#lifecycle-regressions) when changing this code.
- Authenticate and capture identity through the same boundary on initial and
recovery handshakes. Bound abandoned unauthenticated listeners where the
protocol permits it; that deadline must not expire authenticated idle sessions
@@ -373,8 +359,9 @@ stages that never ran.
analysis snapshot is part of `open_binary`; cancellation keeps that operation
and the caller's reason through the shared JSON reader.
- For cancellable observations, carry cancellation through result consumption
and awaited cleanup. Before returning success, check the signal after the
last awaited finalization step.
and awaited cleanup. Check the signal after the last awaited finalization step
unless the operation has passed its documented commit cutoff. Preserve the
owning operation's committed outcome and receipt after that cutoff.
Retain collected observations under typed cancellation. Preserve an existing
primary failure and let incomplete cleanup retain its own classification.
Preserve the caller's abort reason as the typed cancellation error's cause,
+17 -1
View File
@@ -44,6 +44,22 @@ file memory regions and paths (`NT_FILE`), fault signal and code (`NT_SIGINFO`),
auxiliary vectors (`NT_AUXV`) across 32-bit and 64-bit images. Other owners or unparsed
notes keep `core` null.
Linux `CORE` decoding requires System V/unspecified (0) or GNU/Linux (3)
OSABI with ABI version zero. An unspecified OSABI alone does not establish
Linux origin. An explicitly different OSABI or ABI version leaves `core` null
and its Linux-specific `type_name` unknown, with a limitation explaining the
profile. Owner/type numbers, descriptor ranges and hashes, GNU-owned notes,
and complete table-examination coverage remain available.
For Android `NT_ANDROID_TYPE_IDENT` (`.note.android.ident`, owner `Android`,
type `1`) notes, `android.android_api` is decoded from both legacy 4-byte
descriptors (where `ndk_version` and `ndk_build_number` remain null) and modern
132-byte or extended NDK descriptors, which also populate `android.ndk_version`
and `ndk_build_number` when their 64-byte slots hold NUL-padded
printable ASCII. Truncated or non-ASCII Android descriptors degrade `android`
to null while preserving the raw descriptor digest and preview, and other
owners keep `android` null.
`PT_NOTE` and `SHT_NOTE` are examined independently. The same file range may
appear twice when both tables declare it.
@@ -54,7 +70,7 @@ the image never carried notes in another container or overlay.
The selected file is limited to 64 MiB by default (512 MiB maximum). At most
32 note entries are examined by default across every table. Retained note
names, section names, GNU descriptor text, and core dump string representations share a scan budget based on
names, section names, GNU descriptor text, core dump string representations, and Android ident strings share a scan budget based on
the source bytes plus any decoded section-name table, capped at
`max_file_bytes`. The raw source and decoded table must also fit together
within that ceiling. If admission fails, the error reports the required
+7 -5
View File
@@ -22,9 +22,10 @@ use the current projection identity; there is no pre-coverage FIT summary varian
A FIT is a flattened devicetree (FDT v16 or v17) with a top-level `/images`
node. Recognition walks the structure block within the first 4 KiB of the file
only; the file name does not matter. A devicetree whose `/images` node begins
after 4 KiB, a devicetree without `/images`, and any other FDT version stay on
the plain devicetree route: `open_binary` refuses them and
[`inspect_devicetree`](devicetree.md) still parses them. A U-Boot control DTB
after 4 KiB or a devicetree without `/images` stays on the plain devicetree
route: `open_binary` refuses it and [`inspect_devicetree`](devicetree.md)
can parse it when its FDT version is 16 or 17. Other FDT versions are not
recognized as FIT and are also unsupported by `inspect_devicetree`. A U-Boot control DTB
that contains `/images` is treated as a FIT. The container format is `fit`.
Recognition is a probe. The complete devicetree parse decides, so a file whose
@@ -124,8 +125,9 @@ Failures apply to the whole file and return no partial inventory.
The devicetree, including any embedded image data, must be at most 16 MiB; a
larger `totalsize` fails as a memory limit. Store large images externally
(`mkimage -E`): external data of any size is streamed from the file and never
loaded into memory. A FIT may declare at most 1,024 images and 1,024
(`mkimage -E`): external image bytes are streamed from the file within their declared
32-bit sizes and the resource bounds below, without loading the whole image
into memory. A FIT may declare at most 1,024 images and 1,024
configurations, and an image at most 8 hash nodes; the devicetree parser's
node, property and depth bounds also apply. The sum of declared image sizes
is bounded by the shared archive expansion budget. These are fixed resource
+98 -65
View File
@@ -439,6 +439,19 @@ descriptors, and a pefile-compatible import hash of the standard import table.
A missing import directory is observed absence of that table. See
[PE import and delay-load tables](../pe-imports.md).
Inspect a Windows Shell Link (`.lnk`) without resolving or executing the
target:
```bash
rea inspect-windows-shortcut /absolute/path/to/shortcut.lnk --json
```
The workflow reports header flags and FILETIMEs, IDList items, LinkInfo volume
and network names, StringData arguments and icon location, ExtraData blocks
including Tracker droid facts labelled derived, and derived observations such
as argument length and a minimized ShowCommand. See
[Windows Shell Link shortcuts](../guides/native/windows-shortcut.md).
Inspect ELF PT_NOTE and SHT_NOTE tables without executing the image:
```bash
@@ -449,6 +462,32 @@ The workflow reports note owners, types, descriptor hashes, and GNU build-id
or ABI-tag fields when those descriptors match. A missing note table is
observed absence of those declarations. See [ELF note tables](../elf-notes.md).
List ELF and Mach-O initializer and finalizer functions without executing the
image:
```bash
rea inspect-native-initializers /absolute/path/to/program --json
```
The workflow reports `DT_INIT`, init/fini arrays, legacy `.ctors`/`.dtors`, and
Mach-O `__mod_init_func`, `__init_offsets` and `__mod_term_func` entries with
their resolved targets. Universal Mach-O files need `--architecture`. See
[ELF and Mach-O initializer functions](../guides/native/native-initializers.md).
Inspect ELF unwind function ranges without executing the image:
```bash
rea inspect-elf-unwind-ranges /absolute/path/to/program --json
```
The workflow reports FDE start, end, and size, the containing section, an exact
symbol name when one exists, CIE identity, LSDA, and personality. Coverage
counts ranges that match a symbol, ranges without a symbol, and whether the
`.eh_frame_hdr` search table agrees with the decoded FDEs. `.debug_frame` is
reported present, absent, or incomplete and is not decoded. A missing unwind table is
observed absence of those declarations. See
[ELF unwind function ranges](../guides/native/elf-unwind-ranges.md).
Inspect an Apple `.ips` crash report without executing a target:
```bash
@@ -476,6 +515,22 @@ applicable. gzip, xz, and zstd containers are unsupported and name
utility, then inspect the decompressed file. See
[Linux kernel modules](../kernel-modules.md).
Read a Linux kernel image's version banner and embedded `CONFIG_IKCONFIG`
build config without executing it:
```bash
rea inspect-kernel-build-config /absolute/path/to/vmlinux --json
rea inspect-kernel-build-config /absolute/path/to/bzImage --name CONFIG_MODULE_SIG --json
```
The workflow reports the banner version, builder, and compiler, the config
option count, and paged `CONFIG_*` entries (`y`, `m`, strings, numbers, and
`not_set`). An `IKCFG_ST` string counts as a config only when a valid gzip
member follows it and `IKCFG_ED` follows that member. A gzip bzImage payload
is inflated and searched; other payload codecs are unsupported and name
`external_decompression` as the next probe. See
[Linux kernel build config](../guides/native/kernel-build-config.md).
Inspect a CPython 3.7–3.13 `.pyc` header and nested marshal code objects (3.14 and
3.15 headers are qualified but their marshal layout is not pinned)
without executing bytecode or installing Python:
@@ -596,10 +651,11 @@ be verified. See [MCP contracts](../reference/mcp-contracts.md) for session life
[Ghidra first-query deadlines](../reference/mcp-contracts.md#ghidra-first-query-deadlines-and-recovery)
for import, client timeouts and recovery.
A one-shot command releases its provider session and REA runtime before it
prints a failure, so it omits the same-session reuse and
`update_analysis_settings` guidance an MCP connection receives. Its
`details.limit` reports `scope: "rea-invocation"` and
A one-shot command attempts provider-session and runtime cleanup before reporting
a failure. If cleanup remains incomplete, inspect the reported resources and
follow the error's remediation. [Same-session cleanup retry](../reference/mcp-contracts.md#retained-cleanup-retry),
reuse and `update_analysis_settings` apply to a live MCP connection.
For one-shot commands, `details.limit` reports `scope: "rea-invocation"` and
`applies_at: "next_invocation"`; set the named `environment` (or the per-call
`parameter`) for a new invocation and rerun. For example, a Ghidra decompile
deadline names `REA_GHIDRA_DECOMPILE_TIMEOUT_SECONDS`.
@@ -628,12 +684,10 @@ an exact result when the target bytes, operation, parameters, provider and
settings match. Mutations and cursor-dependent calls are excluded from the
cache. Snapshot files are local and use owner-only permissions.
One-shot binary CLI Evidence reports the exact path argument in `caller_input_path`,
including relative spelling and symlink aliases. Its subject identifies the
inspected artifact; `caller_input_path` does not change the Evidence ID or
snapshot query. A replay reports the current invocation's path while leaving
the saved Evidence unchanged. Provider inspections continue to include the
established `parameters.input_path` field.
A binary CLI replay reports the current invocation's selected path while leaving
the saved Evidence and snapshot query unchanged. See
[caller-selected paths](../reference/mcp-contracts.md#caller-selected-paths)
for primary and auxiliary path fields and their relation to Evidence identity.
Importing an Evidence bundle refreshes retained request and subject display metadata.
It preserves cached analysis results, including observations for other targets.
@@ -1139,6 +1193,23 @@ of the serve command's stopped document. See
[agent environments](../agent-environments.md#export-a-bundle) for the folder
layout and what the smoke task checks.
`rea environment-export` prints the written files and exits `0` on success.
Input-pair refusals, an occupied destination, a missing package tarball, and
invalid labels fail before writing output. Host permission failures identify
whether reading or writing was denied and retain the affected path.
A failure during writing can leave a partial folder. Inspect it before removing
it and retrying; the next attempt refuses a non-empty destination. When one
file caused the failure, the diagnostic names that file. A folder-sync failure
can report only its cause.
If `details.partial_observation.kind` is `environment-bundle-publication`, the
bundle was already published. Its `directory` and `files` record the committed
output, even when a later identity check or cleanup failed. Inspect that bundle
and resolve the reported failure before using or replacing it; the receipt is
not an instruction to delete published output. Cleanup resources remain a
separate obligation.
## Compare an environment with its application
`rea environment-compare <manifest.json> --evidence <capture.json> --probe <probe.json> [--probe <probe.json> ...]`
@@ -1330,62 +1401,17 @@ retains failed stages for retry; the CLI exposes no separate retry command.
or prints the refusing stage's structured error and exits `1`, writing nothing
when the refusal comes before the bundle is written. SIGINT cancels it with a
`cancelled` error; a cancellation before the bundle stage writes nothing.
`rea environment-export` is one-shot: it prints the written files and exits
`0`, or prints a structured `invalid_request` error and exits `1` for the same
pair refusals, a non-empty or file-occupied directory, a missing package
tarball or a name that is not a kebab-case label or is a Windows device name,
writing nothing in each case. A file occupying the destination is reported as
requiring a directory; identity-change diagnostics are reserved for admitted
paths that fail later identity checks. Host permission failures identify whether
input reading or bundle writing was denied and retain the reported path.
A write that fails after the first file (a permission, disk-space or
pathname-length failure on a later path) propagates as the host's failure,
naming its cause and, when it failed on one bundle file or the package
tarball, that file. A failure while syncing the finished folder names only its
cause. Either way the partial folder stays in place for inspection; remove it
before retrying, since the next attempt refuses the non-empty directory.
A `cancelled` result does not by itself determine the exit status. Commands
that handle SIGINT or SIGTERM assign `130` or `143` after their operation and
cleanup settle; their structured result can be printed before that status is
assigned. Read the process status and typed result separately.
A `cancelled` result does not by itself determine the exit status; it depends on
the command's signal handling. Commands routed through the shared
`withCommandCancellation` handler in the CLI set status `130` for SIGINT or
`143` for SIGTERM after their operation settles. Current source registrations
use that handler for process capture and comparison (`capture-process`,
`compare-process-captures`), desktop application capture and state
(`capture-desktop-application`, `inspect-desktop-application-state`,
`export-desktop-application`, `describe-desktop-application-task`), JavaScript application analysis (`analyze` when it
selects the JavaScript lane, and `analyze-javascript-application`), selected
browser, web and Electron commands (including `analyze-web-bundle`,
`observe-web-execution`, `capture-browser-scenario` and
`capture-electron-scenario`), and the platform and provider command families
for Android/ADB, Apktool/JEB/Flutter, firmware, PCAP and signal analysis,
WASM/EVM, Go/Rust and binary diagnostics, Frida instrumentation, the Cutter
command, objdump, Rizin and GDB, and the agent environment server
(`environment-serve`). The handler also wraps `doctor`,
`inspect-sqlite-database`, `recover-javascript-sources`,
`inspect-il2cpp-metadata`, and `inspect-desktop-application`. In these paths, a returned structured
`cancelled` result can be printed before the wrapper assigns the
signal-derived status. This describes the current source routing; it is not a
claim that every command or provider runtime has been independently exercised.
Commands with `--evidence_output` select their delivered view, then publish the
complete Evidence bundle atomically. Cancellation before publication leaves no
new file. A publication that has committed can win a later cancellation; the
`cancelled` result then keeps the written path and byte count under
`details.diagnostics.evidence_bundle`. If staging cleanup stays incomplete
after commit, the `cleanup_incomplete` error reports the same file as
`details.published_path` and `details.bytes`.
When a failure retains a completed observation and no bundle committed,
`details.source_closure` states what that observation cites. `publication` is
`not_published`. `records` holds authentic source Evidence this invocation
captured, within 64 KiB. `omitted` lists up to 64 other identities and
`omitted_count` the total: `not_captured` means the invocation holds no such
record, so nothing is shown for it or its ancestors; `not_inlined` means it was
captured but is not in this response. `complete` is true only when every cited
record is in `records` or embedded in the observation. If examining the closure
itself fails, `collection_failure` names the error type and the closure state is
unknown; the original failure is still returned. Nothing is retained after exit,
and running the command again is a new observation.
Commands with `--evidence_output` save the complete Evidence bundle before
delivering the selected view. For committed-file receipts, retained partial
Evidence and missing source records, see
[Evidence publication and source recovery](../reference/mcp-contracts.md#evidence-publication-and-source-recovery).
Other outputs have their own receipt shapes; for example,
[environment export](#export-an-environment-bundle) reports a published directory.
When the reader of piped output closes early, as `rea ... | head` does, the
CLI stops writing, prints no error and exits `141` (`128 + 13`, the status of a
@@ -1461,3 +1487,10 @@ Bun standalone executables use the existing `inspect-artifact` and
`extract-artifact` commands to inventory and materialize embedded source,
sourcemaps and bytecode without running the executable. See
[Bun standalone executables](../bun-standalone.md) for layout coverage and limits.
Deno compile executables use the same commands to inventory and materialize the
embedded virtual filesystem, remote modules, and recorded options. Inventory retains
embedded environment-file values and certificate bytes in local Evidence with their
counts and byte lengths, and extraction does not write them as files. The npm snapshot
length is reported and not decoded, and the executable is not run. See
[Deno compile executables](../deno-standalone.md).
+41 -2
View File
@@ -7,6 +7,7 @@ Setup previews configuration changes and asks for approval before applying them.
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| Connect an agent | [Start setup](#start-setup), then [review changes](#review-setup-changes) |
| Install a Claude Code/Codex plugin | [Agent plugins and marketplaces](#agent-plugins-and-marketplaces) |
| Run unreleased code | [Run REA from a checkout](#run-rea-from-a-checkout) |
| Diagnose one task | [Scoped readiness checks](#check-readiness-for-your-task) |
| Configure an analysis engine | [Hopper](#hopper), [Ghidra](#ghidra), the [IDA guide](../providers/ida-provider.md), or [Kuna](../kuna-provider.md) |
| Update or remove REA | [Maintenance](#diagnose-update-and-remove) |
@@ -384,14 +385,22 @@ Select the part you want to check:
| One analysis engine | `rea doctor --provider ghidra --json` (or `hopper`, `ida`, `jadx`, `kuna`) |
| One agent registration | `rea doctor --client codex --json` (see [client IDs](#supported-agents)) |
| Installed workflow instructions | `rea doctor --skill --json` |
| Desktop app environment builds | `rea doctor --provider desktop_build --client claude_code --json` |
A scoped report has `scope.mode: "explicit"`. Its `scope_checks` determine
`healthy` and the exit status. Other checks appear in `informational_checks`;
`environment_healthy` summarizes the full audit. `--target` adds a target check,
but the report remains audit-wide unless a scope option is also supplied.
Provider checks read the terminal running doctor. A client-started server may
receive a different environment, and doctor cannot observe it. When an available
With one selected client, Ghidra, IDA, JADX and Kuna provider checks use the
client's recorded environment over the terminal it inherits. If that registration
cannot be read or a setting a provider needs cannot be resolved, its available
value is `null` and its check is `unknown`; its configured value is also `null`
when the configuration setting itself is unknown. Doctor does not infer
readiness from the terminal. A missing registration still uses terminal settings
for setup. Other checks, including Hopper, use the terminal running doctor. A
client-started server may receive a different environment, and doctor cannot
observe it. When an available
provider relies on a setting that a registration's file does not record, or
records with other text, doctor adds a non-blocking
`registration_environment:<client>` check with `classification: "unknown"`. The
@@ -595,6 +604,36 @@ feature selection. The same package version string in a development checkout
does not establish that its bytes match the npm tarball. Update a registration
through a reviewed, scoped setup plan, then restart/reconnect the agent.
### Run REA from a checkout
To run code that is not released yet, build a checkout with the Node.js
version in `.nvmrc`:
```bash
git clone https://github.com/morluto/rea.git
cd rea
npm ci
npm run build:cached
```
Then run `npm link` once in the checkout to put its `rea` on your `PATH`, or,
wherever these docs say `rea …`, run
`node /absolute/path/to/rea/scripts/rea.mjs …`. Setup run this way registers
the checkout's `scripts/rea.mjs` with your agents.
After `git pull`, run `npm ci` and `npm run build:cached` again. If the
checkout's skill changed, refresh each installed copy before restarting its
agent. For example, preview and review the Claude Code skill changes:
```bash
rea setup --skill-client claude_code --dry-run --json
```
Then apply the reviewed changes with `rea setup --skill-client claude_code --yes --json`.
Substitute the relevant skill client; use the checkout's
`node /absolute/path/to/rea/scripts/rea.mjs` form if `rea` is not linked. For desktop builds, also pack the [build computer's runtime
archive](../desktop-build-computer.md#requirements) again.
## Skill-only installation
```bash
+2 -2
View File
@@ -1,7 +1,7 @@
# GameCube DOL analysis through Ghidra
This lane imports 32-bit big-endian PowerPC GameCube/Wii DOL images through
Ghidra. It does not execute the image. DOL is a headerless format with no magic
Ghidra. It does not execute the image. DOL has a section and entry-point header but no magic
number, so REA never detects it: the caller must select it explicitly.
Only the cached MEM1 window `0x80000000..0x81800000` is admitted. Wii MEM2
@@ -29,7 +29,7 @@ MCP, with the existing `open_binary` tool:
}
```
The architecture comes from the DOL header (`powerpc`). Do not pass
Selecting the DOL format supplies the architecture (`powerpc`). Do not pass
`architecture` with `gamecube-dol`; it is rejected. `entry_point` is optional,
and if given it must equal the header entry.
+7 -3
View File
@@ -113,8 +113,8 @@ existing analysis families directly, for example
| `push_adb_file` | **mutates device** | One local file to a device path (e.g. pushing tools into `/data/local/tmp`); checks for existing targets and refuses them without explicit overwrite (the check is not atomic); compares digests when device `sha256sum` is available |
| `install_adb_package` | **mutates device** | Local APK via `adb install [-r]`; preserves its Success/Failure verdict, records `replace_requested`, and leaves actual replacement `null` because prior package state is not observed |
| `uninstall_adb_package` | **mutates device** | Requests package removal for user 0 via `adb shell pm uninstall --user 0`, without data retention |
| `start_adb_app` | **mutates device** | Resolves the package's launcher activity (`cmd package resolve-activity --brief`) and starts it (`am start -n`) |
| `start_adb_activity` | **mutates device** | Starts an intent (`am start -a` with optional URI, component, and up to 16 typed extras); preserves the activity manager's verdict |
| `start_adb_app` | **mutates device** | Resolves the package's launcher activity (`cmd package resolve-activity --brief`) and starts it (`am start -W -n`) |
| `start_adb_activity` | **mutates device** | Starts an intent (`am start -W -a` with optional URI, component, and up to 16 typed extras); preserves the activity manager's verdict |
| `stop_adb_app` | **mutates device** | Force-stops every process of a package, ending a dynamic-analysis run |
Screen capture validates the PNG signature, IHDR framing, dimensions, and IHDR
@@ -188,7 +188,7 @@ and during shutdown.
property value remains available in `properties`.
- **Device paths are not host paths.** `base_apk_device_path` values live on
the device filesystem. Only pulls and captures produce host-local paths,
each paired with byte size and SHA-256 digest. A pulled file's host name is
with byte size and SHA-256 digest on success. A pulled file's host name is
the device path's final POSIX segment. REA preserves the original device
path and filename; a missing final segment or `.`/`..` is refused before
output creation. Windows hosts follow [Windows filename rules](https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file),
@@ -249,6 +249,10 @@ and during shutdown.
- Pull and capture outputs are additive: the destination must not already
exist. Re-running a completed pull refuses the existing directory instead
of overwriting evidence.
- If a single-file pull fails and REA observes a regular file at the destination,
the error includes its `local_path` with `transfer_status: "unconfirmed"`
and `digest_status: "unknown"`. The file remains in place; the receipt does
not establish that the transfer completed.
- Cancellation during a package pull preserves caller-selected output. The
error includes partial observations identifying completed artifacts and the
interrupted local path; remaining APKs were not attempted.
+2 -1
View File
@@ -545,7 +545,8 @@ and each upstream request and reply collected before the failure. Failed replies
remain available even when their payload cannot be interpreted. Cancellation
also stops target hashing before provider admission.
These operations do not execute the APK or provide split APK/AAB handling,
The JADX package, class, method and reference operations do not execute the APK
or provide split APK/AAB handling,
signature validation, full resource-table semantics, native-library analysis or
Android runtime capture. An `.aab` suffix is a ZIP archive, not an APK, so
Android tools and the application graph do not treat it as a standalone APK.
+14 -3
View File
@@ -90,9 +90,20 @@ column limit. The selected database is readable and is not reported as
malformed; request fewer columns per call instead. `row_limit`
requires `table`, defaults to 20 and accepts positive safe integers. Samples
remain subject to the byte and worker resource limits below, regardless of row count. The result reports
the selected limit, returned count and whether more rows were observed. Row
order is unspecified; a truncated sample does not prove anything about omitted
records. View, virtual-table and shadow-table row reads are unsupported.
the selected limit, returned count and whether more rows were observed.
Rows are read in a stated unique order reported as `rows.order`: `rowid` for
rowid tables, and `primary_key` for `WITHOUT ROWID` tables, reusing the
primary-key index's own direction and declared collation. `rows.row_offset`
reports the rows skipped before the window and `rows.next_row_offset` the offset
to request for the following page; it is `null` once the window reaches the end.
Pass `row_offset` (CLI `--row-offset`, requires `table`, default 0) to skip into
a table rather than repeating earlier rows. A table that declares all of
`rowid`, `_rowid_` and `oid` as columns and has no primary key reports
`order: "unspecified"` and refuses a non-zero `row_offset`, because the skipped
prefix would be arbitrary. Pages compose only while the reported database and
WAL SHA-256 match; re-inspecting a changed snapshot restarts the sequence.
View, virtual-table and shadow-table row reads are unsupported.
SQLite integers are decimal strings so every signed 64-bit value survives JSON
serialization. Real values retain their numbers; `"Infinity"`, `"-Infinity"`
@@ -265,6 +265,9 @@ retained arrays and counters without invoking application iterators or Array
species.
Listener-chain recognition distinguishes owned, unowned and unknown metadata.
Only a directly owned wrapper establishes hook dispatch. An application's data
link to an owned wrapper remains unknown: `.listener` can name that wrapper
without invoking it.
Data links may be inherited; absence is established only after completing the
bounded prototype lookup. Exhausting either walk, encountering a getter or seeing a Proxy leaves
ownership unknown. The hook preserves native registration without adding another
@@ -50,6 +50,9 @@ A path-filtered reference reports the caller-selected path while keeping its
shared node identity. Item selection also accepts any retained path when it
identifies one module; if several module kinds share that path, select the
reported `node_id`. Node-ID selection uses the stable representative path.
Exported symbol bindings reuse the `javascript-module` kind but name one export
of their owning module, so module pages, items, and summary counts include only
module units and an exported module never becomes an extra path candidate.
## Retained module facts
@@ -223,6 +226,12 @@ registrations/removals and dispatch, Node timers and cancellation handles, async
`node:child_process` creation and ownership, configuration sources and direct
defaults, request construction and response consumers, parse/coercion/
validation boundaries, and built-in resource acquisition/release.
For `fs/promises.open`, a binding receiving the Promise is distinct from one
receiving the awaited FileHandle. Awaiting the Promise later does not replace
the original binding, but `h = await h` can replace it with the FileHandle.
Receiver writes can therefore retain a candidate release and its ownership
ambiguity; a still-known Promise has no direct FileHandle release. Acquisitions
remain retained, and unknown loader authority keeps its existing candidate tag.
Reassignments connect retained right-hand reads to the binding or property
write. Compound assignments also retain the previous-value input; logical
assignments keep conditional inputs as candidates. These edges describe
@@ -22,7 +22,9 @@ rea analyze-javascript-application /absolute/path/to/apps/app.asar \
Generic `rea analyze` selects this static provider for directories and `.asar`
paths when neither `--provider` nor `--snapshot` is supplied. The dedicated
command and the generic route return their complete results inline. Native
command and the generic route return complete results inline by default.
Summary and route-view delivery export the full Evidence to `--evidence_output`
and return a projection; see [route delivery](../../javascript-route-inventory.md). Native
targets, single JavaScript files, `.app` bundles, and explicit deep-provider or
snapshot requests retain the native deep-analysis route.
@@ -86,6 +88,11 @@ properties and remains readable without migration.
## Select sources before analysis
Explicit `source_paths` retain the acquisition owner's requested order, including
selected dependency files. First-party priority applies only to unscoped analysis.
Recovered syntax or incomplete semantic examination keeps Electron coverage
partial even when useful windows or IPC facts were retained.
For a question about known entry sources, supply exact artifact-relative file
paths in `source_paths`, or repeat `--source-path` on either CLI route:
@@ -181,7 +188,9 @@ coverage, limitations, and `normalized_result.parent_evidence_id`. Pass that ID
to `inspect_analysis_view` for module pages or items, or to the application
workflows as a retained reference. The summary does not repeat or truncate the
analysis; a server without session retention refuses summary detail with
`capability_unavailable`. CLI output is unchanged and always complete.
`capability_unavailable`. On the CLI, `--detail summary --evidence_output PATH`
exports the full Evidence and returns its summary; the default remains complete
inline delivery.
With a connected MCP `client` and the caller-selected absolute `inputPath`, this
recipe analyzes once and pages module identities using the returned ID:
@@ -323,6 +332,12 @@ failure does not authorize expanding relationships that parent admission decline
## What is reconstructed
Electron `BrowserView` and `WebContentsView` expose `webContents` and accept
`webPreferences`, including declared preloads. `BaseWindow` has neither surface
of its own. Preload associations retain the parsed constructor's mechanism rather
than labeling every view as a BrowserWindow. These are static associations, not
proof that a renderer or preload executed.
The projector reuses the content-addressed artifact inventory and safe artifact
readers. It retains canonical artifact-relative paths, exact byte counts,
SHA-256 digests, inventory IDs, ASAR container identity, and `.asar.unpacked`
@@ -515,6 +530,25 @@ If fingerprint construction reaches its structural
bound, the fingerprint is unavailable and its status is `truncated`; a bounded
prefix is never presented as a complete stable fingerprint.
## Cached-data compilation boundaries
The [feature specification](../../specs/javascript/v8-cached-data/spec.md) defines
the static admission and uncertainty contract.
A `node:vm` compilation reports whether `cachedData` is declared, absent or
unknown. Explicitly supplied undefined bytes are treated as absent; shadowed
identifiers remain declarations. Source syntax alone does not establish valid cache bytes, V8 acceptance
or execution. The summary counts declared compilations, not executions.
A proven synchronous filesystem read or awaited promise-based read supplies a
cache path. The producer retains its path base: source-directory expressions
can name inventoried artifacts, while relative literal paths depend on the
target working directory and remain unresolved. Other supplied values retain
their bounded source expression. Declared paths, exact-file lookup
status, candidate paths and resolution limitations remain separate; an unresolved
path never becomes a resolved file. Opaque inventoried cache bytes can remain
unavailable to the JavaScript resolver even when their occurrence is known.
## Authority and unknowns
API identity is a derivation: a familiar method or property name does not
@@ -141,7 +141,7 @@ variants of one file remain separate observations. Older Evidence may omit
## Node and Electron roles
The caller declares one role: `node`, `electron-main`, `electron-preload`, or
The caller may declare one role: `node`, `electron-main`, `electron-preload`, or
`electron-renderer`. Node and Electron-main declarations require a protocol
target of type `node`; preload and renderer declarations require `page`.
Inspector does not authenticate the operating-system PID or distinguish an
+121
View File
@@ -0,0 +1,121 @@
# V8 code cache inspection
`inspect_v8_code_cache` reads one explicitly selected V8 code cache container as static
bytes: a bytenode `.jsc`, the bytes `vm.Script.createCachedData()` writes, or a cache
carried inside a Node single-executable application or an Electron app. It never executes
the file, never starts a V8 runtime, never installs bytenode, and never invokes a
decompiler.
```bash
rea inspect-v8-code-cache /absolute/path/to/module.jsc --json
rea inspect-v8-code-cache /absolute/path/to/module.jsc --minStringBytes 8 --json
```
The MCP tool is `inspect_v8_code_cache` with the same inputs and the same retained
Evidence.
## What is read
A V8 code cache is a producer-written container, not a documented file format. This reader
admits one container shape and reports everything else as an observation, so a build it
has never seen still yields facts instead of a false parse.
The 32-byte header is eight little-endian 32-bit words. Every word is reported in
`header.fields` with its byte offset, its observed value, the role this reader believes it
has, and how confident that role is:
| Offset | Role | Status |
| -------------- | -------------- | ----------- |
| `0x00` | magic | confirmed |
| `0x04` | version hash | inferred |
| `0x08` | source length | confirmed |
| `0x0c` | flag hash | inferred |
| `0x10` | build constant | inferred |
| `0x14` | payload length | confirmed |
| `0x18`, `0x1c` | reserved | unconfirmed |
`confirmed` means the role is demonstrated by the reader's own tests against the producer.
`inferred` means the word's behaviour is consistent with the role but a different producer
could plausibly differ. `unconfirmed` means the word is reported and nothing more is
claimed.
Only three facts gate admission:
1. the header size this reader pins (32 bytes);
2. the V8 code cache magic high half, `0xc0de`. The low half is
`ExternalReferenceTable::kSize` and varies per V8 build, so it is reported as a build
fingerprint and never required to match a fixed value;
3. the declared payload length must equal the bytes that follow the header exactly.
`header.source_length` is the producer's recorded source length in UTF-16 code units.
V8's serializer calls this field the source hash; on the producers measured here its value
equals the source length exactly, including sources whose UTF-8 byte length differs, so the
reader reports it under the name the measurement supports. Treat that name as an
observation, not as a claim about what any other build stores there.
`header.producer` names the producer family from the flag bits in that word. Bit 29
marks `vm.compileFunction` (`compile_function`); bit 30 marks `vm.SourceTextModule`
(`module`). When neither flag is present, the producer remains `unknown`:
`vm.Script`, bytenode output and older unflagged function caches cannot be
separated by those bits alone. The source-length mask is `0x1fffffff`, so both
flags sit outside the reported length. This describes the admitted header
profile rather than a version-independent V8 ABI.
## Failed inspection and provenance
After a stable read completes, format and observation-budget refusals retain a
`file-snapshot-hash` partial observation with the selected path, exact SHA-256 and
byte count. This proves which bytes were read; it does not claim the format was
successfully decoded. A refusal before read completion does not invent an identity.
Descriptor cleanup remains owned for retry if finalization fails.
## Embedded byte patterns
`embedded_strings` lists printable runs found in the payload, each with its absolute byte
offset in the selected file and its observed byte length. `min_string_bytes` (default 4)
sets the shortest reported run; `max_strings` caps how many may be reported, and exceeding
it fails without partial success.
These are **byte-pattern observations inside serialized V8 heap data, not parsed heap
objects**. A reported run is not proof V8 retained it as a string. A literal that is absent
from the payload is not proof it is absent from the program: V8 may encode a string in a
form the run scan does not surface, and a string can be produced at runtime rather than
retained.
A run longer than 4096 bytes is reported with `truncated: true` and a `retained_bytes`
prefix.
## Limitations
Every result states these, and they are part of the contract:
- the payload is serialized V8 heap data, not source; no logic is recovered and no
bytecode is decompiled;
- recovering logic needs a version-pinned V8 decompiler (View8-style) that this tool
neither provides nor depends on;
- header roles beyond magic, source length, and payload length are version-dependent
observations;
- the tool never executes the selected file and never claims recovered source.
## Failure behaviour
An unknown magic is a typed `unsupported_target` failure, because the file is not a V8
code cache. A short header, a payload-length disagreement, or bytes past the declared
payload is a typed `invalid_request` failure. Neither produces completed inspection
Evidence; the stable-read partial observation described above is retained when available.
`max_file_bytes` (default 32 MiB, ceiling 64 MiB) is the caller-selected read budget. The
payload SHA-256 is computed over the declared payload, so two containers with the same
payload length and content but different version hashes have different whole-file digests
and identical payload digests.
## Relationship to other tools
- `inspect_binary_layout` reads the surrounding ELF/PE container of a single-executable
application; it does not decode the embedded code cache.
- A cache embedded in a Node single-executable application or an Electron app must be
**extracted first**: this reader admits a container whose magic is at byte zero, so
passing the surrounding ELF/PE executable here returns `unsupported_target`. Run
`extract_artifact` on the application, then pass the extracted `.jsc` path to this tool.
- `inspect_artifact` inventories the file without decoding V8 structures.
- This tool is in the same family as `inspect_python_pyc`, `inspect_erlang_beam`, and
`inspect_kernel_module`: one explicit local file, bounded parsing, no execution.
+5 -8
View File
@@ -212,13 +212,9 @@ rea inspect-managed-members /absolute/path/Assembly.dll --type Namespace.Type \
bundle format. Its parent directory must exist, and it never replaces an
existing path. Relative paths resolve against the command's working directory.
The option also works with complete delivery when a saved bundle is useful.
Summary without a destination is rejected before analysis. A publication failure
returns a typed error with the completed Evidence under
`details.partial_observation`; it does not report successful summary delivery.
Cancellation before publication prevents the new output. Once atomic
publication has started, it can complete despite cancellation; a cancelled
delivery then retains the committed path and byte count under
`details.diagnostics.evidence_bundle`.
Summary without a destination is rejected before analysis. For partial Evidence
and committed-file receipts after failure or cancellation, see
[Evidence publication and source recovery](../../reference/mcp-contracts.md#evidence-publication-and-source-recovery).
Copy `normalized_result.parent_evidence_id` from the summary into the
`source.evidence_id` field of the `managed-members` request above, then save that
@@ -654,7 +650,8 @@ unchanged signature. Comparison retains exact byte-based pairs for malformed
signatures, including empty, truncated, or invalid headers, but reports them as
unknown with a `signature-malformed` limitation when no change is observed.
This applies to historical Evidence without signature-resolution attestation as
well. Runtime-provided methods are counted separately in
well. Runtime-provided methods have the Runtime code type or the InternalCall
implementation flag, as core library FCalls do. They are counted separately in
`native_implementations.runtime_provided`; they have no file-backed native body
for this workflow to map and do not increase `native_body_unresolved`. Historical
verification Evidence without this separate count leaves it unknown (`null`).
+10 -3
View File
@@ -134,9 +134,10 @@ retained, and the effective values are returned in the result limitations. Virtu
Unicorn needs a large virtual map. Limits fail with no partial success, and
owned process/root cleanup completes independently of cancellation.
Core files, GDB session/state/control, optional pwndbg enrichment and instruction
inspection are separate increments tracked by #969. This increment makes no
real support claim for those features or other operating systems/architectures.
For core files and optional pwndbg mapping context, use the
[recorded-crash workflow](recorded-crashes.md). The binary-layout operations
described here do not provide debugger session state or control, or establish
support for other operating systems/architectures.
Typed decoder failures retain bounded `captured_output` (stdout, stderr and an
explicit truncation flag) alongside the original failure category and reason.
@@ -272,6 +273,12 @@ regular files only and rejects symbolic links.
## Byte entropy triage
Entropy admission preserves the caller's spelling in `caller_input_path`. On
Windows, the selected regular file's case-only filesystem spelling is used
consistently in committed paths through both CLI and MCP. Symlink, junction and
short-name aliases are not replaced with a different path. General path
normalization remains lexical and does not probe source-discovered paths.
`inspect_byte_entropy` / `inspect-byte-entropy` profiles any local regular file
without an analysis engine, execution, extraction or network access.
+177
View File
@@ -0,0 +1,177 @@
# ELF unwind function ranges
`inspect_elf_unwind_ranges` / `inspect-elf-unwind-ranges` reads `.eh_frame`
and `.eh_frame_hdr` from one selected local ELF32/ELF64 image and lists the
function ranges those tables name. It reads the file without executing it and
does not require a disassembler.
```bash
rea inspect-elf-unwind-ranges /absolute/path/to/program --json
```
The CLI resolves relative paths against the caller's working directory. MCP
requires an absolute filesystem path and preserves that exact selection:
```json
{
"name": "inspect_elf_unwind_ranges",
"arguments": { "path": "/artifacts/program" }
}
```
Pass `--offset` and `--limit` (MCP `offset` and `limit`) to page the ranges.
The default page starts at 0 and returns at most 256 ranges.
## Observations
The inline Evidence result contains the artifact path, SHA-256, and byte
length, plus ELF class, byte order, machine, and object type.
`eh_frame.status` is `present`, `absent`, `incomplete`, or `unknown`. A
present table names its source: `section` when section headers name
`.eh_frame`, or `program` when section headers are missing and
`PT_GNU_EH_FRAME` supplies the bytes. `location` is the file range that was
examined. A `.eh_frame` section that is `SHT_NOBITS` or lies outside the file
is `incomplete` with a null `location`. One that runs past the end of the
file is `incomplete`, `location` is clamped to its in-file bytes, and the
records in those bytes are still decoded. Only the first `.eh_frame` and
`.eh_frame_hdr` section is decoded, and only the first `PT_GNU_EH_FRAME`
program header. A duplicate section, or a duplicate `PT_GNU_EH_FRAME` when no
`.eh_frame_hdr` section supplies the header, keeps `coverage.status` at
`incomplete`.
`eh_frame_hdr` reports version, the three pointer encodings, the `.eh_frame`
pointer, the declared FDE count, and how many binary-search table entries
were decoded. A header section that is `SHT_NOBITS` or extends past the end of
the file is `incomplete` with a null `location` and is not decoded.
`coverage.eh_frame_hdr_agreement` is `agree` when the table has exactly one
row per decoded FDE, the sorted starts match including repeats, and each row
points at a distinct FDE with that start. It is `disagree` otherwise, and
`unavailable` when the header is absent, unknown, or incomplete. Disagreement
is a limitation. The decoded FDEs stay in the result. The search table is
read for at most `max_ranges` rows, and for no more rows than the header bytes
can hold. When the declared FDE count is larger than either bound, the header
is `incomplete`, `table_entries` counts only the rows read, the comparison is
`unavailable`, and a limitation names the cap. A declared count that does not fit
in 32 bits is not decoded: `fde_count` is null, the header is `incomplete`,
and the decoded FDEs stay in the result. A header whose FDE count encoding is
`DW_EH_PE_omit` (`0xff`), as GNU ld writes when it cannot build the search
table, is `present` with a null `fde_count`, no table rows, and comparison
`unavailable`; it does not make coverage incomplete. A header that declares
an FDE count but writes `DW_EH_PE_omit` as its table encoding is `present`
with that count, no table rows, and comparison `unavailable`, and also keeps
coverage complete. A non-zero FDE count under an indirect encoding is the
address of a slot that is not followed, so `fde_count` is null, the header is
`incomplete`, and the table is not read.
When section headers name both `.eh_frame_hdr` and `PT_GNU_EH_FRAME`, the
section is decoded. A limitation names the segment as ignored only when it
declares different bytes than the section. When no `.eh_frame_hdr` section is
named, the header is read from `PT_GNU_EH_FRAME` even if a `.eh_frame`
section is present.
A record whose length word is `0xffffffff` uses the 64-bit extended length
that follows it. In `.eh_frame` the CIE ID and CIE pointer after that length
stay 4 bytes wide.
`DW_EH_PE_datarel` fields in `.eh_frame_hdr` are relative to the header
address. In `.eh_frame` they are relative to the GOT: `DT_PLTGOT` when the
dynamic table names it, otherwise the `.got.plt` or `.got` section address.
A limitation names the base that was used. When no GOT base is declared,
those values are unresolved: the affected record is not reported and
`coverage.status` is `incomplete`.
`debug_frame.status` is `present`, `absent`, `incomplete`, or `unknown`. It
is `unknown` when the image has no section headers or unreadable section
names. It is `incomplete`, with a null `location` and `coverage.status` at
`incomplete`, when the section is `SHT_NOBITS` or its bytes are not all in
the file. The `.eh_frame` results stay in the report. This command does not
decode `.debug_frame`.
`cies` lists the CIEs that the returned page's ranges name, in index order,
so its length never exceeds the page size. Each `cie_index` in `ranges`
matches the `index` of one entry in `cies`. `coverage.total_cies` counts every
decoded CIE, including CIEs no FDE on this page uses. Each CIE reports
version 1 or 3, augmentation, code and data alignment,
return-address register, pointer encoding, LSDA encoding, personality address
when the augmentation carries one, signal-frame and B-key flags, and the byte
length of the CFA program. CFA instructions are counted and not evaluated.
A CIE whose augmentation has a letter other than `z`, `L`, `P`, `R`, `S`, or
`B` is not decoded: the encodings of later letters cannot be trusted, so its
FDEs are not decoded either. A limitation counts those FDEs and coverage is
`incomplete`.
`ranges` is one page of FDEs. Each range has `start`, `end`, decimal `size`,
the containing `SHF_ALLOC` section, an exact symbol name when a symbol starts
at that address, the CIE index, LSDA, and personality. A function symbol is
preferred, then an `STT_GNU_IFUNC` symbol, then an untyped one. An IFUNC name
is the resolver that starts at that address, not the implementation it
selects at run time, and a limitation says so. Symbol names, section names,
and augmentation strings are target-derived and untrusted. Indirect EH
pointers are not dereferenced. An FDE whose initial location is indirect names
a pointer slot, not its function, so it is not reported as a range; a
limitation counts those FDEs and coverage is `incomplete`. An indirect
`eh_frame_ptr` does not locate `.eh_frame`, and the header is `incomplete`.
A search table with an indirect encoding is not read: the header is
`incomplete`, the comparison is `unavailable`, and the table does not bound a
header-located `.eh_frame`.
An encoded pointer whose stored value is zero is a null pointer, as libgcc
reads it: no PC-relative, text, data, or function base is added and an
indirect pointer is not followed. A resolved address, and an FDE `end`,
wraps at the ELF address width (32 or 64 bits), as libgcc's pointer
arithmetic does. A zero LSDA pointer is reported as a null
`lsda`, even when the CIE declares an LSDA encoding. An FDE whose initial
location is zero marks a function the linker discarded. It is not reported
as a range, `examined_records` still counts it, and a limitation counts how
many were skipped. In a relocatable object an unrelocated initial location
is also zero, so those FDEs are skipped too.
`page` reports `offset`, `limit`, `returned`, `total`, and `next_offset`.
`next_offset` is null when the page reaches the end of the decoded list.
`coverage` counts every decoded range, every decoded CIE, how many ranges
match a symbol, and how many do not. `examined_records` counts CIE and FDE records visited, including
records that could not be decoded.
A missing `.eh_frame` section and a missing `PT_GNU_EH_FRAME` segment are
observed absence of those declarations. That absence is not proof the image
has no functions. Program headers come from the shared ELF section
directory, which rejects an image whose program-header table cannot be read,
so a missing `PT_GNU_EH_FRAME` is always observed absence. When section
headers are missing too, section names are unknown, so a missing header is
`unknown` rather than `absent`.
A `.eh_frame` located only through the `.eh_frame_hdr` `eh_frame_ptr` has no
section size, so it is read up to the end of its `PT_LOAD` segment. Other
data, such as `.gcc_except_table`, can follow it there. When the search table
was decoded, the scan stops after the last FDE the table names, as libgcc's
`PT_GNU_EH_FRAME` lookup only binary-searches that table. Later bytes are not
decoded and a limitation says so. Without a usable table, the scan stops at
the first record that fails to decode, as libgcc's linear FDE search does,
and `coverage.status` is `incomplete`. A CIE with an unrecognized
augmentation letter, or an FDE that uses one, also stops that scan. Reaching the end of the segment with
no terminator also keeps coverage `incomplete`, because the table's extent is
then unknown.
Addresses map to file offsets through `SHF_ALLOC` sections, then `PT_LOAD`
segments. A section without `SHF_ALLOC`, such as `.comment` or `.debug_*`,
is not loaded, so its `sh_addr` is never used for translation and it is never
reported as the section containing a range. A record that ends past the table, or non-zero bytes after
the terminator, keeps `coverage.status` at `incomplete`. Relocatable objects
stay incomplete because relocations are not applied.
## Limits and failures
The selected file is limited to 64 MiB by default (512 MiB maximum).
`max_ranges` defaults to 8192 and caps at 65536. That ceiling applies
separately to CIE records and to FDEs. Exceeding either budget fails without
partial success. One page returns at most 4096 ranges. Symbol lookup stops
after 65536 entries across `.symtab` and `.dynsym` combined. Reaching that
cap keeps `coverage.status` at `incomplete`. Only symbols at decoded FDE
starts are kept, and a name is decoded only for a returned range. The names
on one page share a fixed 16 MiB text allowance; a page that exceeds it fails
with a resource error whose recovery is a smaller `limit`, because
`max_ranges` and `max_file_bytes` do not raise it.
Malformed ELF headers fail without partial success. This workflow does not
execute the image, evaluate CFA programs, or follow indirect pointers.
+151
View File
@@ -0,0 +1,151 @@
# Linux kernel build config
`inspect_kernel_build_config` / `inspect-kernel-build-config` reads the
`Linux version` banner and the embedded `.config` from one selected local
kernel image without executing or booting it. Accepted inputs are a `vmlinux`
ELF, a raw arm64 `Image`, an x86 `bzImage` or `zImage` whose payload is gzip,
and a `configs.ko` module. It does not require a Linux host,
`extract-ikconfig`, or `/proc/config.gz`.
```bash
rea inspect-kernel-build-config /absolute/path/to/vmlinux --json
rea inspect-kernel-build-config /absolute/path/to/bzImage --name CONFIG_SECURITY_SELINUX --json
```
The CLI resolves relative paths against the caller's working directory. MCP
requires an absolute filesystem path and preserves that exact selection:
```json
{
"name": "inspect_kernel_build_config",
"arguments": { "path": "/artifacts/vmlinux", "name": "CONFIG_MODULE_SIG" }
}
```
## Observations
The inline Evidence result contains the artifact path, SHA-256, and byte
length. `format` is `elf` when the file starts with the ELF magic and `file`
otherwise.
`banner` is the first printable string that starts with `Linux version `
followed by a version token beginning with a digit and ends at a NUL or
newline within 512 bytes. `version` is that token. `builder` is the first
parenthesized group (`user@host`). `compiler` is the second group up to the
last `) #`, so nested parentheses in compiler strings are kept. The banner is
`absent` when no such string was found in the searched bytes and `unknown`
when the bytes were not searched.
`config` is `present` only when all of the following hold:
- `IKCFG_ST` is immediately followed by a gzip member (`1f 8b 08`).
- The member inflates within `max_config_bytes` and its CRC-32 and ISIZE
trailer match.
- The member trailer ends exactly at the first `IKCFG_ED` after the gzip
header. Inflation reads only the bytes up to that marker.
- Every non-blank line of the inflated text is a `#` comment,
`# CONFIG_X is not set`, or `CONFIG_X=value`, and the text is valid UTF-8
with no control bytes other than tab, CR, and LF.
An `IKCFG_ST` string that is not followed by gzip magic, or whose complete
member is not followed by `IKCFG_ED`, is skipped, so an ordinary string is never
reported as a config. When `IKCFG_ST`, gzip magic, and a later `IKCFG_ED` frame
a member that does not decode, a deflate stream cut off by that marker, a
member that fails its CRC-32 or ISIZE check, or text that fails the grammar,
the config is `malformed` with coverage
`incomplete`, and `marker`, `gzip`, and `end_marker` locate the blob. A
malformed blob is never reported as an absent config. A valid config later in
the searched bytes still wins. `marker`, `gzip`, and `end_marker` give
the three ranges. `sha256` hashes the inflated text. `option_count` counts
every `CONFIG_*` line. `matched_count` counts the options that match the
optional exact `name` filter, and `entries` is the `offset`/`limit` page of
those matches in file order.
Each entry has a `name`, a `kind`, and a `value`:
| `kind` | Source line | `value` |
| --------- | -------------------------- | ------------------------- |
| `y`, `m` | `CONFIG_X=y`, `CONFIG_X=m` | `y` or `m` |
| `number` | decimal or `0x` hex | the text as written |
| `string` | `CONFIG_X="..."` | decoded text (`\"`, `\\`) |
| `not_set` | `# CONFIG_X is not set` | `null` |
Banner text and configuration values are target-derived and untrusted.
## bzImage payloads
A file with `HdrS` at offset `0x202` is an x86 setup header. From boot
protocol 2.08, `payload_offset` and `payload_length` locate the compressed
kernel after the `(setup_sects + 1) * 512` setup code. `payload` reports the
container, codec, file range, and inflated length. A gzip payload is inflated
within `max_payload_bytes` and the inflated bytes are searched. Locations in
those bytes have `space: "inflated_payload"` and are offsets in the inflated
payload, not file offsets. Only the leading gzip member is inflated, and its
own ISIZE trailer gives the inflated length. Kbuild appends a separate 4-byte
size only for the non-gzip codecs. Any bytes after the gzip member inside the
payload are not read.
xz, lz4, lzma, zstd, bzip2, and lzo payloads are `unsupported`. The result
names the codec and `external_decompression` as the next probe. This is an
external step, not a REA operation: decompress the payload with the matching
utility into a separate file, then call `inspect_kernel_build_config` on that
file. A file that is itself a compressed stream, including a whole-file gzip
such as `Image.gz`, is reported as `unsupported` with its codec and is not
inflated. Only a gzip payload inside a bzImage is inflated.
## Limits and failures
The selected file is limited to 64 MiB by default (512 MiB maximum). An IKCFG
member may inflate to 4 MiB by default (32 MiB maximum) and a bzImage payload
to 128 MiB by default (512 MiB maximum). At most 16384 `CONFIG_*` options are
examined by default (65536 maximum). A page holds 256 entries by default
(4096 maximum). Exceeding any budget fails with no partial success and names
the option to raise. An IKCFG member past `max_config_bytes` fails that way only
when no later candidate is accepted, so an oversized decoy cannot hide a valid
config.
One search inflates at most 16 `IKCFG_ST` gzip candidates and at most four
times `max_config_bytes` of output across them. A candidate whose stream fails
partway through is charged its full per-candidate allowance, since its partial
output is not measured. When that search budget runs
out before a config is accepted, the config is `incomplete` with reason
`config_search_exhausted` instead of failing or reporting an absent config.
Inflation runs off the event loop. Every scan, including marker
searches that find nothing, config text checks, validation of one long value,
and hashing, yields to it at least once
per MiB, so a cancellation that arrives while the image is being parsed is honored
at the next check. One inflate call runs to its output bound once started.
Results that could not search or read the kernel bytes stay `incomplete`,
`malformed`, or `unsupported` and are never
reported as an absent config:
| `config.reason` | Meaning |
| ---------------------------------- | ---------------------------------------------------------------------------- |
| `config_gzip_invalid` | a framed `IKCFG_ST` gzip member does not decode or fails its CRC-32 or ISIZE |
| `config_text_invalid` | a framed `IKCFG_ST` gzip member is not `.config` text |
| `config_gzip_truncated` | an `IKCFG_ST` gzip member runs past the searched bytes |
| `config_search_exhausted` | decoy candidates used up the config search budget |
| `payload_truncated` | the declared bzImage payload or its gzip member ends early |
| `payload_gzip_invalid` | the bzImage gzip payload fails to inflate or its trailer |
| `payload_codec_unsupported` | a compressed payload or whole-file stream was not inflated |
| `unrecognized_payload_codec` | the bzImage payload starts with no known codec magic |
| `setup_header_payload_unavailable` | the setup header predates 2.08 or has no payload length |
A kernel built without `CONFIG_IKCONFIG` carries no embedded config, so an
`absent` config describes only the bytes that were searched. A kernel built
with `CONFIG_IKCONFIG=m` keeps the config in `configs.ko`; inspect that module
instead of the image. This workflow does not execute the image, compare the
config with a source tree, or evaluate Kconfig dependencies.
## Format references
The markers follow Linux v6.12's
[`kernel/configs.c`](https://github.com/torvalds/linux/blob/v6.12/kernel/configs.c)
and
[`scripts/extract-ikconfig`](https://github.com/torvalds/linux/blob/v6.12/scripts/extract-ikconfig).
The setup header fields follow the
[x86 boot protocol](https://docs.kernel.org/arch/x86/boot.html). The banner
format follows
[`init/version-timestamp.c`](https://github.com/torvalds/linux/blob/v6.12/init/version-timestamp.c).
These references establish the decoded layout, not runtime behavior.
+178
View File
@@ -0,0 +1,178 @@
# ELF and Mach-O initializer functions
`inspect_native_initializers` / `inspect-native-initializers` lists the
functions that one local ELF or Mach-O image declares to run before `main` and
at exit. It reads the file without executing it and does not need a
disassembler provider.
```bash
rea inspect-native-initializers /absolute/path/to/program --json
rea inspect-native-initializers ./Universal.app/Contents/MacOS/App --architecture arm64 --json
```
The CLI resolves relative paths against the caller's working directory. MCP
requires an absolute filesystem path:
```json
{
"name": "inspect_native_initializers",
"arguments": { "path": "/artifacts/program", "offset": 0, "limit": 64 }
}
```
A universal Mach-O requires `architecture` to select one slice. ELF files and
thin Mach-O files do not take it.
## Sources
ELF entries are listed in this order:
| Kind | Source |
| --------------- | ------------------------------------------------------------------------------------- |
| `preinit_array` | `DT_PREINIT_ARRAY` / `DT_PREINIT_ARRAYSZ`, else `.preinit_array` |
| `init` | `DT_INIT` |
| `init_array` | `DT_INIT_ARRAY` / `DT_INIT_ARRAYSZ`, else `SHT_INIT_ARRAY` or `.init_array*` sections |
| `ctors` | legacy `.ctors` and `.ctors.*` sections |
| `fini` | `DT_FINI` |
| `fini_array` | `DT_FINI_ARRAY` / `DT_FINI_ARRAYSZ`, else `SHT_FINI_ARRAY` or `.fini_array*` sections |
| `dtors` | legacy `.dtors` and `.dtors.*` sections |
Section fallback applies when the dynamic tag is absent, as in static
executables and relocatable objects. Mach-O entries come from sections typed
`S_MOD_INIT_FUNC_POINTERS` (`mod_init`), `S_INIT_FUNC_OFFSETS`
(`init_offsets`) and `S_MOD_TERM_FUNC_POINTERS` (`mod_term`).
## Entries
Each `entries[]` item reports:
- `slot_va`, `slot_file_offset`, `slot_bytes` and `slot_section`: where the
pointer or offset is stored. For a universal Mach-O, file offsets are
relative to the whole file, not the slice. For `init` and `fini` the slot is
the `DT_INIT` / `DT_FINI` value field in the dynamic section. When that field
is outside every load segment, `slot_va` and `slot_section` are null and a
limitation says so.
- `value_va`, `value_file_offset` and `section`: the resolved target address,
its file offset and its containing section. These are null when the value
was not established. A file offset is also null when load segments map the
address ambiguously (overlapping segments with different file offsets, or
file and zero-fill memory), and the report is then `incomplete`.
- `symbol`: a defined symbol whose value equals the target exactly, or the
import name of an unresolved symbolic relocation or chained bind.
- `resolution`: how the value was obtained.
| Resolution | Meaning |
| ------------------- | -------------------------------------------------------------------- |
| `raw` | The stored word, used when no relocation or fixup covers it |
| `relative_addend` | An `R_*_RELATIVE` relocation addend (RELA, or the REL in-place word) |
| `relr` | A `DT_RELR` packed relative relocation |
| `symbol_addend` | A section relocation against a defined symbol plus its addend |
| `chained_fixup` | A Mach-O chained-fixup rebase target |
| `dyld_info_rebase` | A Mach-O `LC_DYLD_INFO` rebase opcode target |
| `offset_table` | A 32-bit `__init_offsets` value added to the image base |
| `unresolved_import` | A relocation or bind against an undefined symbol |
| `unresolved` | A slot whose value this inspection cannot establish |
A bound import name over the 1024-byte name budget is reported as no name and
makes the report `incomplete` with a counted limitation.
Symbol and section names are untrusted file text and carry
`trust: "observed-untrusted"`.
For PIE executables and shared objects the array slots are usually zero on
disk. A slot is reported `unresolved`, never as its stored zero, when the
dynamic relocation tables use an encoding this inspection does not decode
(for example Android packed relocations or an unsupported machine). Relative
relocations are decoded for x86-64, i386, AArch64 and 32-bit ARM. A slot is
also `unresolved` when a dynamic relocation writes only part of it, starts
inside it, or writes it more than once with different values.
Section `REL` / `RELA` tables are applied to slots that no dynamic relocation
covers. When such a table is skipped for an unexpected entry size, cannot be
read, or lies past the record budget, every slot it could reach that has no
relocation found is `unresolved`, and a `.ctors` slot is not dropped as a
sentinel. A section record that writes only part of a slot, starts inside it,
or repeats it also leaves the slot `unresolved`. In a relocatable object a
table reaches only the section named by its `sh_info`. In a linked image, a relocation section without `SHF_ALLOC`
(such as one kept by `--emit-relocs`) was already applied by the static
linker, so the slot's stored word is used rather than applying the record
again.
An absolute relocation against an `STT_GNU_IFUNC` symbol is `unresolved`: the
symbol value is the resolver, and the loader stores whatever the resolver
returns.
On 32-bit ARM (ELF `EM_ARM` and Mach-O `CPU_TYPE_ARM`), bit 0 of a function
pointer selects Thumb state. `value_va` keeps the pointer as stored, while
`value_file_offset` and `section` describe the code address with that bit
cleared. A Mach-O symbol is matched at either address.
In a relocatable object (`ET_REL`) every section starts at address 0. Slot
and value addresses are offsets inside the named section, and a limitation
says so.
Mach-O pointer slots are decoded through chained fixups or `LC_DYLD_INFO`
opcodes for linked little-endian arm64 and x86-64 images. Other linked images,
including 32-bit ones, have no fixup decoder here: their stored word is used
only when the image declares no `LC_DYLD_INFO` bind stream, and a pointer slot
is `unresolved` otherwise. Legacy external relocations (`LC_DYSYMTAB`
`nextrel`) are not decoded, so they make an otherwise raw pointer slot
`unresolved` in any image. In an object file (`MH_OBJECT`), each section's own
relocation entries set the slot: a pointer-width `UNSIGNED` entry against a
defined symbol gives `symbol_addend`, one against an undefined symbol gives
`unresolved_import`, a section-ordinal entry keeps the stored address, and any
other entry leaves the slot `unresolved`. An `arm64_32` image that declares a
64-bit header is rejected as malformed, since its pointers are four bytes.
`.ctors` and `.dtors` values `0` and `-1` are list sentinels and are omitted.
`-1` means all ones at the image's pointer width: `0xffffffff` in ELF32 and
`0xffffffffffffffff` in ELF64. A 64-bit slot holding `0xffffffff` is listed.
A stored zero in an initializer array is listed, so the array length stays
visible.
## Paging and limits
`offset` and `limit` page the ordered list (default limit 64, maximum 4096).
`coverage.examined_entries` counts every slot read, including omitted
sentinels, and `total_entries` (the listed entries) is set when the inventory
is complete. At most 65536 slots are examined; beyond that, or when relocation
coverage is unknown, `status` and `coverage.status` are `incomplete`.
ELF symbol names come from at most 65536 symbols across all `SHT_SYMTAB` and
`SHT_DYNSYM` tables together, and section `REL` / `RELA` relocations from at
most 1048576 records across all relocation sections together. Mach-O symbol
names come from at most 65536 symbols across all `LC_SYMTAB` commands
together; a repeated `LC_SYMTAB` over the same ranges is ignored with a
limitation. Reaching any of these budgets makes the report `incomplete` with a
limitation.
A symbol name that cannot be read, because its string table is missing or its
offset lies outside the table, is reported as no name and makes the report
`incomplete` with a counted limitation. Name offset 0 is the empty name.
The dynamic relocation tables are read in steps that yield to other work and
observe cancellation, so a large `DT_RELR` table does not block the server.
`limitations` lists the standing limitations, then at most 24 distinct
observations from the image. Reasons a crafted table can repeat per row, such
as symbol names over the 1024-byte budget or relocation sections with an
unexpected entry size, are reported once with a count, and observations past
the 24-note budget are counted in one closing line. The list never exceeds 40
lines.
The selected file is limited to 64 MiB by default (`max_file_bytes`, 512 MiB
maximum). Malformed headers, multiple `PT_DYNAMIC` segments and truncated
dynamic sections fail without partial success.
This inspection does not prove that a listed address runs, and file order is
not the runtime order: `DT_FINI` is listed before `fini_array`, while the
dynamic linker runs `fini_array` first, and `.ctors` runs in reverse order. A
missing tag or section is observed absence of that declaration, not proof that
no code runs before `main`.
Legacy Mach-O bind lookup examines at most 4096 candidate runs per query and
at most twice the file byte count across the decoded image's queries. These
resource allowances bound sparse, overlapping run descriptions without expanding
them into per-address objects. Exhaustion leaves pointer applicability unresolved
and the report incomplete. Bind-stream parsing and initializer batches yield so
other requests and cancellation can run.
@@ -332,6 +332,10 @@ crashed run can be recovered by the next run. Failed descriptor or staging clean
could not be written or read, for example on a full disk, the export stops with
an error instead of decompiling the rest. Files and records already committed
stay, `decompile-index.json` is still written, and a later resume continues.
If the index was published before cancellation or a later failure, the error's
`diagnostics.published_output` retains its `output_directory` and `index_path`.
This receipt confirms publication, not completion of every selected function.
Failed staging cleanup retains the same receipt through cleanup retry.
Type inspection selects one exact database pathname or typed data address.
Struct/union fields, enums, pointers, arrays, typedefs, size, alignment, packing
@@ -1131,6 +1135,9 @@ original JSON scalar types. Values that JSON cannot represent faithfully,
including unsafe integers, negative zero and non-finite numbers, remain null
with a path-specific gap and incomplete capture coverage. Null alone does not
establish that an accessibility value was successfully read or absent.
Failed role, title, value or action reads add a path-specific gap and mark the
capture truncated. An empty `actions` array with an action-read gap means the
available actions are unknown.
An initial PID or window mismatch is `invalid_request` on `pid` or
`window_id` and leaves provider availability intact. A selected window that
+94
View File
@@ -0,0 +1,94 @@
# Windows Shell Link shortcuts
`inspect_windows_shortcut` / `inspect-windows-shortcut` answers whether one
selected local file is a Windows Shell Link (`.lnk`), which target path,
arguments, working directory, and icon location it records, which volume and
network names `LinkInfo` stores, and which ExtraData blocks follow the
strings. It reads the file without resolving or executing the target and does
not require a Windows SDK, COM, or a network.
```bash
rea inspect-windows-shortcut /absolute/path/to/shortcut.lnk --json
```
The CLI resolves relative paths against the caller's working directory. MCP
and the advertised input schema require an absolute filesystem path and
preserve that exact selection:
```json
{
"name": "inspect_windows_shortcut",
"arguments": { "path": "/artifacts/shortcut.lnk" }
}
```
## Observations
The inline Evidence result contains the artifact path, SHA-256, and byte
length. `header` is the 76-byte `ShellLinkHeader`: `LinkFlags` and
`FileAttributes` as raw values plus documented names, creation/access/write
FILETIMEs as a raw 64-bit decimal and ISO-8601 UTC when the timestamp is in
range, file size, icon index, `ShowCommand` (`normal`, `maximized`, or
`minimized`), and hotkey modifiers. Undocumented `ShowCommand` values are
decoded as `normal`, as specified.
`id_list` is present when `HasLinkTargetIDList` is set. Each item keeps its
file offset, size, and type byte. Root-folder, volume, and file-entry items
are decoded when those layouts match documented shell-item headers, including
the 8.3 short name on a file entry. Every other item is `raw` with a SHA-256
of its payload. Unknown items are not guessed.
`link_info` reports volume drive type, serial, label, local base path, and
common network relative link names, with Unicode variants when the header
declares them. ANSI strings use a byte-preserving Latin1 projection; the
original system ANSI code page is unobserved.
`string_data` reports name, relative path, working directory, command-line
arguments, and icon location according to `LinkFlags`, each with encoding,
`CountCharacters`, byte length, and the decoded value. `IsUnicode` selects
UTF-16LE; otherwise the Latin1 projection is used.
`extra_data` enumerates every block: signature, size, and offset.
`EnvironmentVariableDataBlock` and `IconEnvironmentDataBlock` expose ANSI and
Unicode targets. `TrackerDataBlock` exposes the NetBIOS machine id and droid /
birth-droid GUIDs. Version-1 UUID MAC and timestamp values are labelled
`evidence_kind: "derived"`. `KnownFolderDataBlock` and `SpecialFolderDataBlock`
keep their folder identifiers. `ConsoleFEDataBlock` keeps the code page.
`PropertyStoreDataBlock` and unrecognized signatures stay raw with SHA-256.
Unknown signatures are listed and are not dropped.
`observations` are derived only from those documented fields: whether
arguments are present, argument character length, target extension, whether
`ShowCommand` is minimized, and whether the icon location differs from the
recorded target path. That comparison is `null` unless the icon and a recorded
target are both full paths: a stored filename, relative path, or `%VAR%` form
cannot show that two locations differ. This workflow does not emit verdicts
about intent.
A missing optional section is observed absence of that structure. It is not
proof the shortcut never carried that data in another container.
## Limits and failures
The selected file is limited to 1 MiB by default (16 MiB maximum). At most 256
IDList items (4096 maximum) and 64 ExtraData blocks (1024 maximum) are
examined by default. Retained string payload bytes across StringData,
LinkInfo, and ExtraData are limited to 64 KiB by default (1 MiB maximum).
Malformed `HeaderSize` or `LinkCLSID`, and exhausted budgets, fail without
partial success. Truncation after a valid header, ExtraData size overruns, and
odd Unicode lengths return partial coverage with `coverage.failing_offset`.
A LinkInfo offset that points outside its structure is reported at the
offset field itself, so every issue offset lies inside the file.
Coverage is never `complete` when issues are present.
The selected path must be a regular file. Symbolic links are rejected.
UNC paths and other host-prefixed device paths, such as `\\server\share\a.lnk`
and `\\?\UNC\server\share\a.lnk`, are rejected before any filesystem call. On
Windows, a path whose parent directory is a symbolic link or junction is
rejected before anything follows that link. The check covers the directories
Windows opens after removing `.` and `..`, so `C:\alias\..\real\a.lnk` is
checked at `C:\real` only; a `\\?\` path is checked as written. A mapped
network drive cannot be told apart from a local drive by its path and is not
rejected.
This workflow does not resolve, open, or execute the link target or call COM,
and it does not contact a network for a path on a local volume.
+22 -7
View File
@@ -35,11 +35,13 @@ different recovery: reinstall REA for the active platform, architecture, and
Node.js version with optional dependencies enabled. Capability diagnostics
distinguish this from the Windows capture-adapter limitation.
macOS also requires Apple's Swift compiler through `xcrun` for process
ownership inspection. REA compiles its packaged, narrow process-inspection
helper into a private temporary directory before a capture or owned provider
process starts; the same prerequisite applies to owned provider-process
supervision on macOS. REA removes that directory when it exits. REA does not
macOS also requires REA's process-inspection helper for ownership inspection.
REA reuses a verified cached helper or compiles one with the selected Swift
toolchain before a capture or owned provider process starts; the same
prerequisite applies to owned provider-process supervision on macOS.
Per-process temporary helper directories are removed on exit; the verified
cache persists. See [helper and toolchain configuration](#scenario-and-result-details)
for cache validation and compiler overrides. REA does not
install Xcode, Command Line Tools, or other software. Capability checks prepare
this helper before reporting macOS capture as available.
@@ -97,6 +99,18 @@ process observations under a shared comparison contract. It reports observed
differences with their locations, while residual unknowns or truncated
observations prevent a complete-equivalence claim. Matching scenario
commitments do not reveal whether redacted sensitive inputs were equal.
The MCP tool accepts each complete capture inline or as an exact
`{"kind":"retained-evidence","evidence_id":"ev_..."}` reference to capture
Evidence already retained by the current session.
Capture-local observer timing remains in Evidence for provenance, but scheduler
and observation latency alone do not make behavior changed: terminal,
interaction-dispatch, settlement/finalization, process-sample, and filesystem
checkpoint times are excluded from the default semantic equality projection.
To make a timing value part of the question, supply a `trace_spec` whose exact
event includes that field. Semantic fields such as output, interaction outcome,
exit status, finalization delivery, process identity/command, and filesystem
contents still participate in the default comparison.
For scenarios where independent scheduling can change event order, the CLI
also accepts an optional trace-specification JSON file as the third argument.
@@ -508,8 +522,9 @@ a representability limit, not a timer limit. The nominal lifecycle budget is tha
sum; polling, snapshotting and cleanup lie outside it. Scenario `events` keep
being dispatched during finalization and are recorded as usual. `finalization_ms`
of `0`, the default, keeps today's behaviour and the committed identity of every
existing scenario. `elapsed_ms` and `sent_at_ms` are timing data and take part in
exit comparison like `settlement.elapsed_ms`.
existing scenario. `elapsed_ms` and `sent_at_ms` are retained timing provenance
like `settlement.elapsed_ms`. The default semantic comparison excludes these
capture-local times; an exact trace event can assert them explicitly.
Every capture requires `truncation_details`, with separate accounting for:
+2 -2
View File
@@ -120,7 +120,7 @@ correspondence merely from their different retained registrations.
- `compare_web_screenshots` / `rea compare-web-screenshots` performs bounded local PNG pixel comparison without OCR or external services.
- The CLI comparison commands accept each capture, screenshot artifact or normalization policy as inline JSON or a JSON file path. Use files for screenshot artifacts and scenario captures, whose embedded PNG bytes can exceed the host's command-line length limit.
- Every surface has equivalent CLI and MCP contracts and returns Evidence provenance.
- MCP tools return complete results inline and include the Evidence ID. Session evidence can be exported with `export_evidence_bundle`.
- By default, MCP tools return complete results inline and include the Evidence ID. Selected summary views retain the complete parent Evidence and return a projection. Session evidence can be exported with `export_evidence_bundle`.
Target discovery returns the complete in-scope target array in one result.
@@ -228,7 +228,7 @@ in an existing profile.
For such a browser, pass the browser socket instead of the HTTP endpoint:
```bash
rea list-browser-targets ws://127.0.0.1:9222/devtools/browser/<id>
rea list-browser-targets "ws://127.0.0.1:9222/devtools/browser/<id>"
```
Chrome writes the port and the `/devtools/browser/<id>` path to the
+1 -1
View File
@@ -359,7 +359,7 @@ A `request` step sends one HTTP request from the page with the page's own
recorded in the step's network events like any request the application makes.
Use it to record an application's API, including writes, when driving the UI
for each call would be slower or less exact than calling the endpoint the UI
calls. It is the only action that changes application state without a user
calls. This action directly sends a caller-declared HTTP request without a user
gesture, so run scenarios with write requests only against an instance whose
data you may change. This scenario creates one item:
+5 -1
View File
@@ -357,7 +357,11 @@ entire property and its sidecars; a `scope: "property-name"` redaction points
to its actual parent. No substitute property name or child pointer is invented.
Omitted subtrees are still validated, including canonical HAR base64. Explicitly sensitive artifact
paths are empty in Evidence and omitted from locations, while the original
SHA-256 and size remain available unless the digest itself is explicitly excluded. Failure messages, diagnostics and cleanup
SHA-256 and size remain available unless the digest itself is explicitly excluded.
CLI [caller-selected paths](../../reference/mcp-contracts.md#caller-selected-paths)
are excluded independently: a sensitive capture spelling can be omitted while a
safe `descriptor_set_path` remains, and a safe relative spelling can remain even
when its resolved parent path is sensitive. Failure messages, diagnostics and cleanup
resources follow the same explicit declarations without changing error types;
sensitive issue pointers identify a real ancestor instead of a fabricated
coordinate. Header/cookie authentication values and known
+1 -1
View File
@@ -52,7 +52,7 @@ The [documentation directory](README.md) lists every guide by domain.
| Task | Guides |
| --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Identify a desktop installation | [Runtime candidates, evidence and follow-up files](desktop-applications.md) |
| Inspect native functions, references, or types | [Native binaries](guides/native/native-investigation.md), [Go metadata](guides/native/go-binaries.md), [Rust dependencies](rust-binaries.md), [CPython pyc files](python-pyc.md), [PE certificates](pe-certificates.md), [PE imports](pe-imports.md), [PE TLS/load config](pe-load-config.md), [ELF notes](elf-notes.md), [Linux kernel modules](kernel-modules.md), [Apple IPS](apple-ips.md), [Erlang BEAM](erlang-beam.md), [offline ELF layout](guides/native/binary-diagnostics.md), [recorded crashes](guides/native/recorded-crashes.md) |
| Inspect native functions, references, or types | [Native binaries](guides/native/native-investigation.md), [Go metadata](guides/native/go-binaries.md), [Rust dependencies](rust-binaries.md), [CPython pyc files](python-pyc.md), [PE certificates](pe-certificates.md), [PE imports](pe-imports.md), [PE TLS/load config](pe-load-config.md), [ELF notes](elf-notes.md), [initializer functions](guides/native/native-initializers.md), [ELF unwind ranges](guides/native/elf-unwind-ranges.md), [Linux kernel modules](kernel-modules.md), [Linux kernel build config](guides/native/kernel-build-config.md), [Apple IPS](apple-ips.md), [Erlang BEAM](erlang-beam.md), [offline ELF layout](guides/native/binary-diagnostics.md), [recorded crashes](guides/native/recorded-crashes.md) |
| Select a native provider or import format | [Ghidra semantics](providers/ghidra-provider.md), [Windows](providers/windows-ghidra-p0.md), [DOS](providers/ghidra-dos.md), [raw bytes](providers/raw-binary.md), [GameCube DOL](ghidra-dol.md), [MIPS](providers/ghidra-mips.md), [RISC-V](providers/ghidra-riscv.md), [PowerPC](ghidra-ppc.md), [PSP](providers/ghidra-psp.md), [NativeAOT](providers/ghidra-nativeaot.md), [IDA](providers/ida-provider.md), [Kuna](kuna-provider.md), [JEB](providers/jeb-analysis.md) |
| Analyze JavaScript or Electron artifacts | [Static analysis](guides/javascript/javascript-artifact-reconstruction.md), [tracing and comparisons](guides/javascript/javascript-application-workflows.md), [application graph](guides/javascript/javascript-application-graph.md), [source recovery](guides/javascript/javascript-recovery.md) |
| Compare static JavaScript with runtime observations | [Runtime attribution](guides/javascript/javascript-runtime-observation.md), [reconciliation](guides/javascript/javascript-runtime-reconciliation.md), [Electron observation](guides/javascript/electron-observation.md), [Electron fuses](electron-fuses.md) |
+7
View File
@@ -24,6 +24,13 @@ This validates the embedded bundle, not the rest of the snapshot container.
## Configure
Doctor uses the selected client's effective registration environment. An
unresolved setting that affects the probe keeps readiness unknown rather than
falling back to the terminal account. Kuna's home-based cache fallback includes
`USERPROFILE` when `HOME` is absent; an explicit cache root or a selected nonempty
`HOME` makes that fallback irrelevant. These home settings are probe dependencies
and are not persisted as ambient provider registration settings.
```bash
export REA_KUNA_COMMAND=/absolute/path/to/kuna
rea doctor --provider kuna
+5 -1
View File
@@ -58,7 +58,11 @@ fail without partial success. A security directory that ends in fewer than
eight header bytes, including zeros, is a truncated `WIN_CERTIFICATE` and
fails the same way. SignedData must contain at least one `SignerInfo`, and
each `SignerInfo` must carry a non-empty signature value. Each embedded X.509
certificate must include `subjectPublicKeyInfo` and `signatureValue`. Decoded
certificate must include `subjectPublicKeyInfo` and `signatureValue`.
Certificate issuer/subject and signer issuer names require nonempty RDN sets
and exactly two fields (type and value) in each attribute, as defined in
[RFC 5280](https://www.rfc-editor.org/rfc/rfc5280.html#section-4.1.2.4).
Malformed name structures fail before their text is reported. Decoded
certificate name text, serials, validity spellings, and subject key identifiers
share a 64 KiB budget per PKCS#7 payload, and each payload decodes at most
16,384 ASN.1 values. Exhausting either fixed allowance returns a nonretryable
+1 -1
View File
@@ -267,7 +267,7 @@ profile stages before retrying their retained descriptors.
| Function identity | Every function result carries the entry address and Ghidra FunctionManager classification for external, thunk, and resolved thunk target. These are observations, not proof that unresolved targetless calls have been recovered. |
| Assembly and pseudocode | Assembly is complete Ghidra Listing text; pseudocode is Ghidra decompiler output. Neither is original source, and cross-provider comparison never treats Hopper and Ghidra text as equal or unequal semantic facts. |
| Instruction fast path | `read_function_instructions` returns every raw Listing instruction for the requested function without invoking the decompiler or whole-program name/string inventories. |
| Calls and references | Callers/callees contain only resolved functions. Reference edges preserve exact ReferenceManager type and call/jump/data/read/write/indirect/computed/conditional/terminal/external facts. Targetless computed flow remains unknown. Synthetic entry-point references without actionable memory sources are omitted explicitly. |
| Calls and references | Callers/callees contain only resolved functions. Reference edges preserve exact ReferenceManager type and call/jump/data/read/write/indirect/computed/conditional/terminal/external facts. Targetless computed flow remains unknown. A computed call's recorded targets stay observed callees, but they are static candidates rather than an exhaustive set, so callee coverage is `partial` and names those call sites. Synthetic entry-point references without actionable memory sources are omitted explicitly. |
| CFG | Dossiers use `BasicBlockModel` and retain only non-call successors inside the function body. CFG topology is address-normalized for comparison; provider-specific block construction remains a declared difference. |
| P-code value flow | Function dossiers include up to 3,000 high-p-code operations, at most 64 inputs per operation, and 12,000 def-use edges. Results identify memory reads/writes, branches, and calls by p-code opcode, and mark decompiler-dead operations. Large results report truncation, an omitted-operation lower bound, and known omitted-input/edge counts. The dossier is an intra-function graph; `trace_native_values` composes derived parameter/argument and return/output dependencies across resolved calls. It does not resolve memory aliasing, call side effects, runtime behavior, persistent state, or business meaning. |
| Result extent | Function instruction scans and native API boundary observations remain complete. P-code flow is the explicit bounded exception; its count fields distinguish exact retained counts from lower-bound or known-omitted counts. Caller cancellation and provider failures remain distinct. |
+1 -1
View File
@@ -233,7 +233,7 @@ admits it explicitly. Raw-binary and GameCube DOL targets are refused; open
them with Ghidra. Admission is not verification: the real workflows under
[Verification](#verification) cover x86_64 and arm64 only.
All profiles support procedure/string inventory and literal or regex search, procedure resolution, pseudocode, assembly, raw function instructions, resolved callees, incoming address references, and a function dossier. Inventories and modern pseudocode/assembly follow upstream pagination. Upstream limits on modern xrefs and callees are retained as explicit truncation limitations. In the modern headless profile, targets that are not proven x86-only use processor-neutral `callgraph` edges instead of the x86 instruction checks in upstream `callees` (mrexodia/ida-pro-mcp#549). REA requests depth zero: the pinned upstream emits the root's outgoing edges without scanning child functions, then REA batches function-name lookup for those addresses. The graph covers recognized function destinations only; imports and other non-function targets remain unknown. A server without `callgraph` returns an empty relationship list with an explicit coverage limitation. Graph and path workflows retain those limitations alongside observed edges. A failed or inconsistent graph reply remains an error. A transport-level truncated preview is rejected rather than reported as complete evidence; the error preserves upstream retrieval guidance.
All profiles support procedure/string inventory and literal or regex search, procedure resolution, pseudocode, assembly, raw function instructions, resolved callees, incoming address references, and a function dossier. Inventories and modern pseudocode/assembly follow upstream pagination. Upstream limits on modern xrefs and callees are retained as explicit truncation limitations. In the modern headless profile, targets that are not proven x86-only use processor-neutral `callgraph` edges instead of the x86 instruction checks in upstream `callees` (mrexodia/ida-pro-mcp#549). REA requests depth zero: the pinned upstream emits the root's outgoing edges without scanning child functions, then REA batches function-name lookup for those addresses. The graph covers recognized function destinations only; imports and other non-function targets remain unknown. A server without `callgraph` returns an empty relationship list with an explicit coverage limitation. Neither `callees` nor `callgraph` reports the call sites behind its edges, so a computed call's targets are never established as exhaustive; callee coverage is therefore `partial` even for an uncapped reply, and a call path that does not reach its goal remains `unknown`. Graph and path workflows retain those limitations alongside observed edges. A failed or inconsistent graph reply remains an error. A transport-level truncated preview is rejected rather than reported as complete evidence; the error preserves upstream retrieval guidance.
All profiles expose `list_documents` as the single target admitted for the session. Attached mode verifies its digest against IDA metadata before returning it; headless mode binds the digest-checked private input. `inspect_address_context`, `trace_feature`, and `binary_overview` can therefore resolve that identity without upstream document-listing tools. Segment enumeration is optional: when the selected profile cannot provide it, `binary_overview` still returns document and procedure/string counts and omits `segments` and `segment_count`; omission means unobserved, not empty. The modern headless profile also supports `resolve_containing_procedure`. An address resolves through upstream `lookup_funcs` to the canonical entry of the function that contains it; the body stays unavailable like other IDA identities. When no function contains it, REA reads the database-scoped minimal `survey_binary` and reports `not_in_procedure` for an address inside one of its segments (ends are exclusive) and `outside_segments` otherwise. A missing, truncated or inconsistent survey fails the read instead of guessing a reason. `trace_feature` marks a trace truncated, with a residual unknown for that address, when upstream caps the references it returned. Attached profiles do not declare address containment resolution.
+13 -1
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · **العربية** · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
# REA: هندسة عكسية لأي شيء
@@ -84,6 +84,10 @@ npx rea-agents setup
يستخدم MCP مخططات إدخال مختصرة افتراضيًا. للحصول على إرشادات الحقول الكاملة وتفاصيل التحقق المتداخل، اضبط `REA_MCP_INPUT_SCHEMA_PROFILE=full` في تسجيل MCP. يحتفظ الخياران بجميع الأدوات والتحقق القياسي نفسه على الخادم؛ راجع دليل عقود MCP.
يسجّل الإعداد بيئة التشغيل المحددة وملف دخول REA مباشرةً. عند استخدام مشغّل حزم، احتفظ بإدخال ذاكرة التخزين المؤقت وبيئة التشغيل؛ ونفّذ تنزيل الحزمة من دليل موثوق خارج المشروع المستهدف. راجع دليل التثبيت والإعداد.
تُعلن مخططات الإخراج الكاملة افتراضيًا. إذا حدّ عميلك من حجم `tools/list`، فاضبط `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` أو `off` في تسجيل MCP؛ يظل التحقق والخروج المنظّم كاملين على الخادم. راجع قسم مخططات الإخراج في دليل عقود MCP.
### اطلب من وكيلك
```text
@@ -157,6 +161,7 @@ npx rea-agents@latest setup
| بنية ELF دون تشغيل | الأقسام والمقاطع والرموز ومعلومات إعادة التموضع الأصلية، وآليات الحماية المحتملة المستدلّ عليها بالفحص الثابت | pwntools يوفّره المستدعي على Linux x64؛ [تشخيص الملفات الثنائية](../guides/native/binary-diagnostics.md) |
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
| شيفرة EVM البايتية | محددات التوجيه، وإزاحات البايتات، والمعاملات المستنتجة، وقابلية تغيير الحالة | مدخل محلي يحمل بايتات خامًا أو تمثيلًا سداسيًا عشريًا على Linux x64؛ [دليل EVM دون تشغيل](../guides/evm/evm-bytecode.md) |
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
@@ -172,6 +177,7 @@ npx rea-agents@latest setup
| التقاط الحزم | نقاط النهاية وDNS وTLS SNI وتوزيع البروتوكولات وطلبات HTTP | tshark وcapinfos يوفّرهما المُستدعي؛ [دليل pcap](../guides/data/pcap-analysis.md) |
| تجميعات .NET | البيانات الوصفية، وتعليمات CIL، واعتماديات الشيفرة الأصلية المعلنة، ومقارنات البناء | فحص ثابت؛ [دليل الشيفرة المُدارة](../guides/managed/managed-code-analysis.md) |
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
| حزم Android APK | تصريحات ملف manifest، والأصناف، والدوال الناتجة عن فك الترجمة، والمراجع | JADX دون واجهة رسومية وJDK كامل على Linux/macOS/Windows x64؛ [دليل Android](../guides/android/android-analysis.md) |
| أجهزة Android | الأجهزة والحزم والعمليات والسجلات والدامبات ولقطات الشاشة ونقل APK/الملفات | adb يوفّره المُستدعي (محاكي أو جهاز)؛ [دليل ADB](../guides/android/adb-device-analysis.md) |
| مشاريع JEB | وحدات المشروع من المحرك وبصمات المصنّفات والكود الزائف للأنواع/الدوال | عميل JEB يبدأه المُستدعي ويقدّم MCP، ويُختار عبر REA_JEB_MCP_URL؛ [دليل JEB](../providers/jeb-analysis.md) |
@@ -273,6 +279,12 @@ agent-env run ./my-env
[مرجع البيئات](../agent-environments.md) ·
[شاهد العرض على X](https://x.com/reatools/status/2112574822584918075?s=20)
### بيئات تطبيقات سطح المكتب
يستطيع REA أيضًا إنشاء بيئة لتطبيق سطح مكتب على Linux يستخدمه الوكيل عبر لقطات الشاشة والفأرة ولوحة المفاتيح. من طلب من سطر واحد، مثل "أنشئ لي بيئة Gnote يضيف فيها الوكيل زيت الزيتون إلى ملاحظة قائمة التسوق"، يثبّت وكيلك التطبيق على حاسوب بناء محلي، ويكتب المهمة، ويصدّر البيئة، ثم يتحقق من المهمة على حاسوب جديد. يحتاج الجهاز الذي يبنيها إلى Linux على amd64 أو arm64، وDocker، وإصدار إطار agentenv الذي يحدده الدليل.
[إعداد بيئات تطبيقات سطح المكتب](../desktop-build-computer.md)
## الأسئلة الشائعة
<details>
+523
View File
@@ -0,0 +1,523 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · **Български**
# REA: Reverse Engineer Anything
### Един MCP сървър за обратно инженерство на бинарни файлове, приложения и поведение по време на изпълнение.
**Харесва ви функция в някое приложение? Разберете как работи, чак до ниво бинарен код.**
[![Версия в npm](https://img.shields.io/npm/v/rea-agents?style=flat-square&color=cb3837)](https://www.npmjs.com/package/rea-agents)
[![Каталог с MCP инструменти](https://img.shields.io/badge/MCP-tool_catalog-5c4ee5?style=flat-square)](../reference/mcp-contracts.md#generated-catalog)
[![Изисквания за Node.js](https://img.shields.io/badge/Node.js-requirements-339933?style=flat-square&logo=nodedotjs&logoColor=white)](#current-status)
[![skills.sh](https://skills.sh/b/morluto/rea?style=flat-square)](https://skills.sh/morluto/rea/reverse-engineer-anything)
[![Лиценз MIT](https://img.shields.io/badge/license-MIT-f4c430?style=flat-square)](../../LICENSE)
[![Discord](https://img.shields.io/discord/1556595354999332884?logo=discord&logoColor=white&label=Discord&color=5865F2)](https://discord.gg/GkcryMnJDM)
<a href="https://trendshift.io/repositories/82054?utm_source=repository-badge&amp;utm_medium=badge&amp;utm_campaign=badge-repository-82054" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/82054" alt="morluto%2Frea | Trendshift" width="250" height="55"/></a>
**[Уебсайт](https://rea.tools/) · [Ръководства](https://rea.tools/guides/) · [Примери](https://rea.tools/showcase/)**
<a href="https://discord.com/invite/GkcryMnJDM"><img alt="Присъединете се към общността на REA в Discord" src="https://img.shields.io/badge/Join%20us%20on%20Discord-5865F2?style=for-the-badge&logo=discord&logoColor=white" height="40"></a>
[Бърз старт](#бърз-старт) · [Как работи REA](#как-работи-rea) · [Какво можете да анализирате](#какво-можете-да-анализирате) · [Примери](#примери) · [Създаване на RL среди](#build-rl-environments) · [Често задавани въпроси](#често-задавани-въпроси) · [Документация](#документация)
<code>npx rea-agents setup</code>
</div>
> [!IMPORTANT]
> Изтегляйте REA от [morluto/rea](https://github.com/morluto/rea),
> [rea.tools](https://rea.tools/) или [npm пакета rea-agents](https://www.npmjs.com/package/rea-agents).
> Следвайте връзките за инсталиране и издания от тези официални източници. Подобно
> име на хранилище или копиран README не доказва, че дадено изтегляне е официално.
<div align="center">
<br />
<img src="../assets/rea-hopper-analysis.png" alt="REA стартира своя мост за анализ в Hopper, докато изследва нативен бинарен файл" width="1200" />
<br /><br />
<table aria-label="Общността на REA">
<tr>
<td align="center" width="360">
<a href="https://discord.gg/GkcryMnJDM">
<img src="../assets/discord.svg" height="42" alt="Discord" /><br />
<strong>Присъединете се към общността за обратно инженерство</strong>
</a><br />
<sub>Discord · Въпроси и отговори · Покажете какво сте направили</sub>
</td>
</tr>
</table>
<br />
</div>
---
Видели сте функция в приложение и искате същата във вашия продукт? Помолете агента си да я проучи с REA. Той може да изследва приложението без изходния му код, да обясни как работи функцията, да покаже доказателствата и да изгради подобна версия за вашия проект.
REA свързва агента ви с инструменти за изследване на нативни бинарни файлове, JavaScript и Electron приложения, .NET асемблита и уебсайтове. Същите инструменти можете да използвате и от терминала. Анализът се извършва локално, а резултатите включват доказателствата и ограниченията зад всеки извод.
Настройката регистрира REA в агента ви и инсталира съответните инструкции за работния процес. Нативният анализ може да използва вече инсталиран Hopper, Ghidra, IDA или Kuna; по желание настройката може да инсталира Hopper след ваше одобрение. Статичният анализ на JavaScript не изисква двигател за нативен анализ.
> **[Посетете уебсайта на REA](https://rea.tools/)** за инструкции за настройка, илюстрирани ръководства и реални казуси.
## Бърз старт
В Linux стартирането на Ghidra, JADX и инструментите за фърмуер, както и
статичният анализ на JavaScript/Electron, изискват съвместима с procps команда
`ps` в `PATH` на REA за проверките кой процес на кого принадлежи. Стъпките за
отстраняване на проблема са в `docs/getting-started/installation.md`, в раздела
„Linux owned-process prerequisite“.
### Настройте агента си
След като имате инсталирани Node.js и npm, изпълнете:
```bash
npx rea-agents setup
```
Изберете агентите си, прегледайте предложените промени и ги одобрете. Настройката
добавя MCP сървъра на REA и съответните инструкции за работния процес, като прави
резервни копия на съществуващата конфигурация. След това рестартирайте агента.
Настройката записва директно избраната среда за изпълнение и входния скрипт на
REA. Ако сте получили REA чрез инструмент за изпълнение на пакети (package
runner), не изтривайте записа му в кеша. Изтегляйте пакета от доверена
директория извън целевия проект. Подробности за инсталирането и отстраняването на
проблеми има в ръководството за настройка по-долу.
Настройката поддържа Claude Code, Codex, Cursor, Gemini CLI, Grok Build и
[други агенти](../getting-started/installation.md#supported-agents). Вижте
[инсталиране и настройка](../getting-started/installation.md) за конфигуриране на
доставчици на анализ, ръчна регистрация на MCP и инсталиране на плъгина за
Claude Code/Codex.
По подразбиране MCP използва компактни входни схеми, за да заема по-малко от
контекста. Задайте `REA_MCP_INPUT_SCHEMA_PROFILE=full` в MCP регистрацията си,
когато са ви нужни пълните описания на полетата и подробностите за вложената
валидация. И двата профила запазват пълния набор от инструменти и каноничната
валидация на сървъра. Вижте „Compact input schema profile“ в ръководството за MCP
договорите.
По подразбиране се обявяват пълните изходни схеми. Ако клиентът ви ограничава
размера на цялата рамка `tools/list`, задайте
`REA_MCP_OUTPUT_SCHEMA_PROFILE=compact`, за да ограничите всяка обявена изходна
схема, или `off`, за да пропуснете изходните схеми изцяло. И двете настройки
запазват каноничната валидация от страна на сървъра и пълните структурирани
резултати. Вижте „Output schemas“ в ръководството за MCP договорите.
### Попитайте агента си
```text
Разбери как работи търсенето в приложението Notes, покажи ми доказателствата и
изгради подобна функция за моя проект.
```
Заменете Notes с целевото си приложение и функцията, която искате да разберете.
### Използвайте терминала
Изследвайте директорията на разархивирано JavaScript/Electron приложение или ASAR
архив:
```bash
npx -y rea-agents@latest analyze-javascript-application /absolute/path/to/app --json
```
Резултатът включва модули, импорти, границите на Electron и доказателствата за
тях. Заменете пътя с вашата цел, например `"D:/apps/example"` в Windows.
За да инсталирате командата `rea` за редовна употреба:
```bash
npm install --global rea-agents
rea --help
```
За нативен анализ първо конфигурирайте доставчик на анализ. Вижте
[ръководството за CLI и Evidence](../getting-started/cli.md) за нативните
команди, избора на доставчик, моментните снимки (snapshots) и скриптирането.
### Обновяване на REA
REA се променя бързо и новите издания често съдържат поправки на грешки.
Поддържайте инсталацията си актуална.
За CLI, инсталиран с `npm install --global` или `bun add --global`:
```bash
rea update
```
`rea --update` е псевдоним на същия проверен процес и приема същите глобални
флагове за изхода. Използвайте `rea update`, когато го комбинирате с други опции
на командата.
Командите за обновяване запазват общо най-много 4 MiB от stdout и stderr. Твърде
големите отговори с метаданни се отхвърлят след приключване на командата;
подробните (verbose) инсталации продължават с ограничена диагностика. Изходът за
напредъка, предназначен за хора, се съобразява с обратното налягане
(backpressure) на терминала и изчаква изпратените записи да завършат.
Глобалните обновявания чрез Bun изискват Bun 1.2.17 или по-нова версия. При
по-стара версия първо обновете Bun ръчно и след това изпълнете `rea update`.
За да опресните регистрациите в агентите и умението (skill), изпълнете командата
за настройка, която обновяването отпечатва.
Ако използвате `npx`, обновете настройката на агента си с:
```bash
npx rea-agents@latest setup
```
Прегледайте промените от настройката и рестартирайте агента. За еднократни CLI
команди използвайте `npx rea-agents@latest`, последвано от командата. С Bun
използвайте `bunx rea-agents@latest` вместо `npx rea-agents@latest`.
## Как работи REA
Агентът ви извиква REA чрез MCP, за да изследва целта и да проследи съответния
код. REA връща констатации заедно с доказателствата за тях. Агентът ги използва,
за да задава допълнителни въпроси, да обяснява поведението или да напише и тества
реализация. CLI командите използват същите работни процеси.
![Процес на изследване с REA: агентът ви пита за локална цел, REA я изследва и проследява с инструменти за анализ, а агентът използва върнатия код, препратките и неизвестните, за да обясни, реализира и тества.](../../website/public/assets/figures/rea-investigation-flow.svg)
[Отворете фигурата в пълен размер](../../website/public/assets/figures/rea-investigation-flow.svg).
<a id="current-status"></a>
## Какво можете да анализирате
REA изисква Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) или 26.12.1+, както и
npm. Допълнителните инструменти и поддържаните операционни системи зависят от
целта:
| Цел | Какво връща REA | Изисквания и ръководство |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Инсталирани настолни приложения | Кандидати за среда за изпълнение, поддържащи файлове, маркери на компоненти и следващи проверки | Вградена ограничена проверка на директории и заглавни части; [настолни приложения](../desktop-applications.md) |
| Нативни бинарни файлове | Псевдокод, асемблер, низове, символи, извиквания и препратки | Hopper, Ghidra, IDA или Kuna; [нативен анализ](../guides/native/native-investigation.md) |
| Структура на ELF (офлайн) | Секции, сегменти, оригинални символи/релокации и кандидати за статични защитни механизми | Предоставен от вас pwntools на Linux x64; [диагностика на бинарни файлове](../guides/native/binary-diagnostics.md) |
| Go бинарни файлове | Вградена версия на компилатора, модули, замени и настройки на компилацията | Вградена статична проверка на ELF/PE/thin Mach-O; не изисква инсталиран Go |
| GPU кодови обекти | CUDA/HIP цели, избрани параметри и ресурси на ядрата, запазен PTX текст | Вградена статична проверка на ELF/PE/fatbin/CUBIN/PTX; [GPU кодови обекти](../gpu-code-objects.md) |
| Файлове на модели | Метаданни на GGUF / safetensors, декларации на тензори и изчислени общи стойности | Вградена проверка на заглавните части; по желание хеш на целия файл; [файлове на модели](../model-artifacts.md) |
| IL2CPP метаданни | Образи на асемблита от Unity global-metadata.dat, имена на типове и методи и диапазони на индекси | Вградено статично декодиране на версии 24, 27, 29, 31 и 39; не изисква Unity |
| Godot PCK | Опис и извличане на архива, оригинални данни от заглавната част и директорията и идентичност на избрано съдържание | Вградена статична поддръжка на формати 2, 3 и 4; не изисква Godot |
| Rust бинарни файлове | Вградени от cargo-auditable имена на crate-ове, версии, източници и връзки между зависимостите | Вградена статична проверка на ELF/PE/thin Mach-O; [Rust бинарни файлове](../rust-binaries.md) |
| PE сертификати | Записи Authenticode WIN_CERTIFICATE и полета за самоличност на подписващия от PKCS#7/X.509 | Вградена статична проверка на PE; [PE сертификати](../pe-certificates.md) |
| PE импорти | Имена на импортирани и отложено зареждани (delay-load) DLL библиотеки, ординали, IAT RVA адреси и pefile хеш на импортите | Вградена статична проверка на PE; [PE импорти](../pe-imports.md) |
| Windows преки пътища | Цел, аргументи, работна директория и данни от Shell Link | Вградена статична проверка на LNK; [Windows преки пътища](../guides/native/windows-shortcut.md) |
| ELF бележки | Собственици и типове на PT_NOTE/SHT_NOTE, полета GNU build-id и ABI-tag | Вградена статична проверка на ELF; [ELF бележки](../elf-notes.md) |
| Защита на бинарни файлове | PIE, NX, RELRO, CFG и свързаните с тях флагове в заглавните части на ELF, PE и Mach-O | Вградена статична проверка на заглавните части; [защита на бинарни файлове](../binary-hardening.md) |
| Сривове на Apple (IPS) | Метаданни от .ips, нишки, образи, регистри и документирани класове сривове | Вградена статична проверка на JSON; [Apple IPS](../apple-ips.md) |
| Модули на ядрото на Linux | Ключове от .modinfo, CRC стойности от __versions, наличие на this_module и подпис в края на файла | Вградена статична проверка на ELF; [модули на ядрото](../kernel-modules.md) |
| Erlang BEAM | IFF блокове (chunks), атоми, експорти, импорти, ламбди и заглавната част Code | Вградена статична проверка на BEAM; [Erlang BEAM](../erlang-beam.md) |
| WASM артефакти | Валидация, секции, точни WAT форми на импортите/експортите и декодиран WAT | Предоставен от вас WABT 1.0.42; `inspect_wasm_artifact` |
| EVM байткод | Селектори на функции, отмествания в байтове, изведени аргументи и променливост (mutability) | Локален raw/hex носител на Linux x64; [ръководство за офлайн EVM](../guides/evm/evm-bytecode.md) |
| SQLite бази данни | Таблици, колони, индекси, изгледи, тригери и избрани редове от обикновени таблици | Локална моментна снимка на базата/WAL; Node.js 24.x >=24.15 или 26+ с нативни ограничения на SQLite |
| Записани сривове в Linux | Сурови бележки, регистри/сигнали на всяка записана нишка и по желание кандидати за съпоставяне с файлове в паметта | Предоставен от вас pwntools на Linux x64; по желание GDB/pwndbg; [записани сривове](../guides/native/recorded-crashes.md) |
| JavaScript / Electron | Модули, импорти, source maps, маршрути, IPC и връзки с нативни добавки | Node.js и npm; Linux: съвместима с procps команда `ps`; [анализ на приложения](../guides/javascript/javascript-application-workflows.md) |
| Уебсайтове | Структура на страниците, скриптове, мрежови наблюдения и заявени екранни снимки | Браузър от семейството на Chrome; [анализ в браузъра](../guides/web/browser-observation.md) |
| Запазени мрежови записи | Заявки, отговори, открити полезни данни (payloads) и местоположения в изходния код | HAR или Fiddler Everywhere SAZ; mitmdump на Linux за нативен mitmproxy; [ръководство за мрежови записи](../guides/web/web-network-captures.md) |
| .NET асемблита | Метаданни, CIL инструкции, декларирани нативни зависимости и сравнения между компилации | Няма (само статичен анализ); [ръководство за управляван код](../guides/managed/managed-code-analysis.md) |
| Android APK файлове | Декларации в манифеста, класове, декомпилирани методи и препратки | JADX без графичен интерфейс и пълен JDK на Linux/macOS/Windows x64; [ръководство за Android](../guides/android/android-analysis.md) |
| Подписи на APK | Подписващи v1/v2/v3/v3.1, отпечатъци на сертификати, ротация на ключове и вътрешна съгласуваност на хешовете | Няма (само статичен анализ); `inspect_apk_signature` |
| Android устройства | Устройства, пакети, процеси, логове, дъмпове, екранни снимки и прехвърляне на APK/файлове | Предоставен от вас adb (емулатор или физическо устройство); [ръководство за ADB](../guides/android/adb-device-analysis.md) |
| JEB проекти | Единици на проекта от двигателя на JEB, хешове на артефакти и псевдокод на типове/методи | Стартиран от вас JEB клиент, който обслужва MCP и е избран чрез REA_JEB_MCP_URL; [ръководство за JEB](../providers/jeb-analysis.md) |
| Android ресурси | Декодиран манифест, таблици с низове, локали и данни за версията | Предоставен от вас стартер за Apktool; [ръководство за ресурси](../guides/android/apktool-resource-analysis.md) |
| Flutter приложения | Хеш на Dart snapshot, хешове на библиотеките за всяко ABI и произход на компилацията на двигателя | Няма (статичен анализ на APK); [ръководство за Flutter](../guides/android/flutter-analysis.md) |
| Фърмуер | Региони, резултати от извличането и предаване към нативен анализ | Binwalk / Unblob на Linux; [ръководство за фърмуер](../guides/firmware/firmware-analysis.md) |
| Записани пакети | Избрани полета, повтарящи се стойности, филтри и правила decode-as | Linux: TShark 4.x + prlimit; [ръководство за записи](../guides/data/packet-captures.md) |
| Обобщения на пакети | Крайни точки, DNS, TLS SNI, разпределение по протоколи и HTTP заявки | Предоставени от вас tshark и capinfos (проверено на Linux); [ръководство за pcap](../guides/data/pcap-analysis.md) |
| Записани логически сигнали | Анотации от декодерите, диапазони от семпли и диагностика | Linux: sigrok-cli 0.7.2 + prlimit; [записи на сигнали](../guides/signals/signal-recordings.md) |
| Пакети и ресурси | Описи на файлове, хешове, plist файлове, устройство на Apple пакети (bundles) и извлечени ресурси | [Ръководство за артефакти и JavaScript](../guides/javascript/javascript-artifact-reconstruction.md), [Apple приложения](../guides/apple/apple-application-analysis.md) |
| Поведение на процеси | Изход в терминала, взаимодействия, наблюдения на изхода от процеса и на файловата система и сравнения между изпълнения | Linux/macOS с нативен PTY; [запис на процеси](../guides/runtime/process-capture.md) |
| PyInstaller изпълними файлове | Членове на CArchive, версия на Python, входни скриптове и извлечен байткод | Няма (само статичен анализ); [пакетирани Python приложения](../python-packaged-applications.md) |
| Изпълними файлове на Deno | Виртуални файлове, входна точка, опции и размер на npm снимката | Няма (само статичен анализ); [изпълними файлове на Deno](../deno-standalone.md) |
Статичната проверка на JavaScript и .NET чете предоставените файлове, без да
стартира приложението. Записът по време на изпълнение стартира избраната цел или
взаимодейства с нея с правата на вашия потребител; всяко ръководство за анализ по
време на изпълнение описва какво точно прави.
За офлайн проверка на нативни бинарни файлове REA поддържа и предоставени от вас
GNU objdump и Rizin. Вижте
[ръководството за инструменти за обратно инженерство](../reverse-engineering-tools.md)
за настройка на доставчиците, CLI командите и ограниченията на Evidence. REA не
инсталира и не обновява нито един от двата доставчика.
<a id="choosing-a-deep-analysis-provider"></a>
Поддържаните нативни формати и операционни системи зависят от доставчика. Вижте
[настройката на Hopper и Ghidra](../getting-started/installation.md#hopper),
[ръководството за IDA](../providers/ida-provider.md) (включително незадължителен
нативен MCP мост), [ръководството за декомпилатора Kuna](../kuna-provider.md) и
[експерименталната поддръжка на Ghidra за Windows](../providers/windows-ghidra-p0.md).
Ghidra поддържа и [анализ на 16-битов DOS код](../providers/ghidra-dos.md). За
големи бинарни файлове увеличете времето за стартиране на доставчика с
`REA_GHIDRA_STARTUP_TIMEOUT_MS` или `REA_HOPPER_STARTUP_TIMEOUT_MS`. За избора
на доставчик вижте [ръководството за CLI](../getting-started/cli.md#choose-a-provider).
Проверете [наличността в изданията](../getting-started/installation.md#released-package-and-main)
за функции, добавени след последното издание в npm.
## Примери
<a href="https://rea.tools/showcase/">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="../assets/rea-showcases-dark.svg" />
<img alt="Илюстрации на примерите DX-Ball (звукова панорама), Notion (мост за клипборда) и TH04 (пръстен от куршуми)" src="../assets/rea-showcases.svg" />
</picture>
</a>
### DX-Ball: реконструиране на изчислението на звуковата панорама
Проследете извикване на звук до помощната функция, която превръща позицията в
панорама, изследвайте инструкциите и превърнете непълния псевдокод в C.
Реконструкцията минава 3 205 тестови случая спрямо оригиналния x86 код и
възпроизвежда всичките 63 байта на компилираната функция.
[Прочетете казуса](https://rea.tools/showcase/dx-ball/) ·
[Хранилище с реконструкцията](https://github.com/N0zoM1z0/dx-ball)
### Notion: проследяване на моста за клипборда в Electron
Открийте API-то за клипборда в renderer процеса, проследете го през preload
скрипта и IPC до главния процес и изследвайте формата за форматирано съдържание
в клипборда.
[Прочетете казуса](https://rea.tools/showcase/notion/)
### TH04: възстановяване на изчислението на пръстена от куршуми в DOS
Изследвайте 16-битовите инструкции на оригиналната игра за PC-98, възстановете
изчисленията на фиксираните и насочените ъгли и сравнете реконструирания C++ код
с изхода на историческия компилатор.
[Прочетете казуса](https://rea.tools/showcase/th04/) ·
[Хранилище с реконструкцията](https://github.com/N0zoM1z0/th04)
### Създавайте RL среди с REA
Запишете сесия в уеб приложение, превърнете неговото API в инструменти и експортирайте среда, която AI агент може да използва. Стартирайте я с AgentEnv, след което добавете задачи и проверки за награда за RL обучение или оценка.
[Прочетете ръководството](https://rea.tools/guides/rl-environments/) ·
[Гледайте видеото](https://x.com/reatools/status/2112574822584918075?s=20)
Ако сте използвали REA за нещо интересно, ще се радваме да го видим. Споделете
случая си в [issue](https://github.com/morluto/rea/issues) или
[pull request](https://github.com/morluto/rea/pulls), като включите целта,
въпроса си, как ви помогна REA и какво открихте.
<a id="build-rl-environments"></a>
## Създаване на RL среди
Дайте на AI агент локална среда, в която да упражнява задачи като намиране на issue или създаване на папка, без да стартира оригиналното приложение. Използвайте я за обучение с подсилване (reinforcement learning, RL) или за да проверите колко добре агентът изпълнява задачи.
REA превръща записаните API заявки и отговори в инструменти, които агентът може да извиква. Средата използва записаните данни и поддържа промени само когато записът потвърждава ефекта им.
След като REA е настроен в агента ви, заменете примерния URL адрес и задачите с папки по-долу със свои:
```text
Използвай REA, за да изградиш RL среда от тестовото ми уеб приложение на
http://127.0.0.1:3000.
Обхвани извеждането на списък, създаването, преименуването и изтриването на
папки. Можеш да създаваш и премахваш тестови папки. Не променяй съществуващите
данни.
Запази я в папка с име my-env. Провери кои операции работят и ми кажи как да я
стартирам.
```
<details>
<summary>Използвайте командния ред вместо това</summary>
Използвайте тези команди, ако вече имате файл със записаните от браузъра заявки и отговори на приложението. За да стартирате резултата, са нужни и AgentEnv, и Docker.
```sh
rea environment-build ./session.har ./my-env --name my-env --json
agent-env run ./my-env
```
</details>
REA експортира готова за стартиране среда с базов тест, който проверява дали тя стартира и отговаря. Използвайте я с вашата RL рамка, за да зададете целите на задачите, да добавите проверки за награда и да стартирате обучението.
[Изградете среда](https://rea.tools/guides/rl-environments/) ·
[Справочник за средите](../agent-environments.md) ·
[Гледайте демонстрацията в X](https://x.com/reatools/status/2112574822584918075?s=20)
### Среди за настолни приложения
REA може да създаде среда за Linux настолно приложение: агентът го управлява чрез снимки на екрана, мишка и клавиатура. От кратка заявка агентът инсталира приложението, създава задача, експортира средата и я проверява на нов компютър. За изграждането са необходими Linux на amd64 или arm64, Docker и версията на agentenv, посочена в ръководството.
[Настройка на среди за настолни приложения](../desktop-build-computer.md)
## Често задавани въпроси
<details>
<summary><strong>Кои агенти могат да използват REA?</strong></summary>
Всеки агент, който поддържа локални MCP сървъри. Настройката конфигурира
[поддържаните агенти](../getting-started/installation.md#supported-agents);
другите клиенти могат да използват
[ръчна MCP регистрация](../getting-started/installation.md#mcp-registry).
</details>
<details>
<summary><strong>Нужен ли ми е двигател за нативен анализ?</strong></summary>
Задълбоченият нативен анализ използва Hopper, Ghidra, IDA или Kuna в зависимост
от целта и операцията. Статичната проверка на JavaScript и .NET работи без
двигател за нативен анализ. Настройката може да инсталира Hopper след ваше
одобрение; Ghidra, IDA и Kuna се използват от вече съществуващите ви инсталации.
Вижте [настройката на доставчиците](../getting-started/installation.md#hopper)
за възможностите и поддържаните от тях цели.
</details>
<details>
<summary><strong>Трябва ли първо да стартирам Hopper?</strong></summary>
REA стартира Hopper, когато дадена операция се нуждае от него. В macOS при първо
стартиране може да се появи диалогов прозорец, който ви пита дали да изберете
демо режим, или да активирате лиценза си. Завършете този диалог в същата
потребителска сесия преди първата си CLI/MCP операция или задача, която ще се
изпълнява без надзор. При нужда отворете Hopper ръчно. Вижте
[стартиране и отстраняване на проблеми с Hopper](../getting-started/installation.md#launcher-paths-and-troubleshooting).
</details>
<details>
<summary><strong>Какво прави инсталирането на умението (skill) от skills.sh?</strong></summary>
Умението дава на агента ви инструкции как да провежда изследвания. Използвайте
`npx rea-agents setup`, за да регистрирате MCP сървъра на REA и да инсталирате
съответните инструкции, след което рестартирайте агента. Вижте
[инсталиране само на умението](../getting-started/installation.md#skill-only-installation).
</details>
<details>
<summary><strong>Какъв код връща REA?</strong></summary>
Нативният анализ връща псевдокод и асемблер. Анализът на JavaScript/Electron
възстановява модулите и връзките между тях. Агентът ви използва тези
констатации, за да напише и тества реализация; [примерите](#примери) показват
цялостни разработени случаи.
</details>
<details>
<summary><strong>Качва ли REA приложението ми някъде?</strong></summary>
REA анализира целите локално. Агентът ви получава резултатите от инструментите,
а доставчикът на модела, който агентът използва, има собствена политика за
данните.
</details>
<details>
<summary><strong>Какво да направя, ако попадна на грешка?</strong></summary>
Първо обновете; възможно е скорошно издание вече да я е поправило.
За CLI, инсталиран с `npm install --global` или `bun add --global`:
```bash
rea update
```
За настройка на агента чрез `npx`:
```bash
npx rea-agents@latest setup
```
Ако използвате агент, извършете
[опресняването на настройката](#обновяване-на-rea) и го рестартирайте. Опитайте
отново същата задача. Ако проблемът продължава,
[отворете issue](https://github.com/morluto/rea/issues), като посочите версията
на REA, типа на целта, стъпките за възпроизвеждане и изхода с грешката.
</details>
## Документация
Започнете с [практическите ръководства](https://rea.tools/guides/) на уебсайта.
За точните опции, предварителните изисквания и договорите за резултатите:
- [Инсталиране и настройка](../getting-started/installation.md): регистриране на агенти, конфигуриране на доставчици, обновяване и деинсталиране.
- [Готовност и отстраняване на проблеми](../getting-started/installation.md#check-readiness-for-your-task): диагностика на конкретен агент или двигател за анализ.
- [CLI и Evidence](../getting-started/cli.md): команди, избор на доставчик, моментни снимки, импорт/експорт и изходни статуси.
- [MCP договори](../reference/mcp-contracts.md) и [подсказки за агенти](../getting-started/mcp-prompts.md): резултати от инструментите, сесии и насочвани изследвания.
- [Каталог с инструменти](../reference/mcp-contracts.md#generated-catalog): генериран списък с инструменти, доставчици и CLI команди.
- [Пътна карта](../development/roadmap.md): планирана работа и проследяване на възможностите.
Съобщавайте за уязвимости чрез [SECURITY.md](../../SECURITY.md).
## История на звездите
🎉 **400 000 звезди в GitHub — благодарим ви!**
Благодарим на всички, които използват REA, съобщават за грешки, предлагат нови функции, тестват версии и допринасят с поправки.
<a href="https://www.star-history.com/?repos=morluto%2Frea&amp;type=date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=morluto/rea&amp;type=date&amp;theme=dark&amp;legend=top-left" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=morluto/rea&amp;type=date" />
<img alt="История на звездите на REA в GitHub" src="https://api.star-history.com/chart?repos=morluto/rea&amp;type=date" />
</picture>
</a>
## Отказ от отговорност
Вижте [DISCLAIMER.md](../../DISCLAIMER.md) за насоки за отговорна употреба.
Позицията на проекта относно незаконната или неразрешената употреба обхваща
всички версии, канали за разпространение и платформи на REA; всяко копие запазва
приложимите за него лицензи.
REA е предназначен за законни изследвания, обучение, оперативна съвместимост,
съхраняване на софтуер и анализ на софтуер, който притежавате или имате
разрешение да изследвате.
## Принос към проекта
Ще се радваме на помощта ви с REA! [Отворете issue](https://github.com/morluto/rea/issues),
за да съобщите за грешка или да предложите функция, или
[изпратете pull request](https://github.com/morluto/rea/pulls), за да подобрите
кода или документацията.
Вижте [CONTRIBUTING.md](../../CONTRIBUTING.md) за настройка на средата за
разработка и проверките, [тестване](../development/testing.md) за видовете
проверки и [картата на архитектурата](../architecture/architecture.mermaid) за
избрани слоеве и пътища на зависимостите.
## Лиценз
[MIT](../../LICENSE)
Кодът, написан за проекта REA, е лицензиран под MIT. Материалите от трети страни
запазват собствените си лицензи и бележки за авторски права; вижте
[бележките за трети страни](../../THIRD_PARTY_NOTICES.md) за списъка със
зависимости, запазените текстове на лицензите и условията на външните
инструменти.
**Трябва да сте придобили законно търговските инструменти и да имате право да ги
използвате**, включително IDA Pro / декомпилаторите на Hex-Rays, Hopper и JEB,
съгласно приложимите им лицензи. REA не предоставя лиценз, ключ или право на
активиране за нито един инструмент. Пробните и демо версиите остават обект на
условията на производителя, включително ограниченията за брой потребители,
функции, автоматизация и споделяне на резултатите. Кракнати копия, откраднати
ключове, неразрешено споделяне на ключове и заобикаляне на лицензионни
ограничения не са разрешени. Тези насоки не изменят лиценза MIT или лицензите на
трети страни.
+13 -1
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · **Deutsch** · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
# REA: Alles reverse-engineeren
@@ -84,6 +84,10 @@ Die Einrichtung unterstützt Claude Code, Codex, Cursor, Gemini CLI, Grok Build
MCP verwendet standardmäßig kompakte Eingabeschemas. Für vollständige Feldhinweise und Details zur verschachtelten Validierung setze `REA_MCP_INPUT_SCHEMA_PROFILE=full` in der MCP-Registrierung. Beide Profile behalten alle Tools und dieselbe kanonische Servervalidierung; siehe MCP-Vertragsleitfaden.
Die Einrichtung registriert die gewählte Laufzeit und das REA-Einstiegsskript direkt. Bewahre bei einem Paket-Runner dessen Cache-Eintrag und die Laufzeit auf; lade das Paket aus einem vertrauenswürdigen Verzeichnis außerhalb des Zielprojekts. Siehe die Installationsanleitung.
Vollständige Ausgabeschemas werden standardmäßig angekündigt. Begrenzt dein Client `tools/list`, setze in der MCP-Registrierung `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` oder `off`. Servervalidierung und strukturierte Ergebnisse bleiben vollständig. Siehe „Output schemas“ im MCP-Vertragsleitfaden.
### Deinen Agenten fragen
```text
@@ -157,6 +161,7 @@ REA benötigt Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) oder 26+ (>=26.12.1) so
| Offline-ELF-Struktur | Sektionen, Segmente, ursprüngliche Symbole/Relokationen und mögliche Schutzmaßnahmen aus statischer Analyse | Vom Aufrufer bereitgestelltes pwntools unter Linux x64; [Binärdiagnostik](../guides/native/binary-diagnostics.md) |
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
| EVM-Bytecode | Dispatch-Selektoren, Byte-Offsets, abgeleitete Argumente und Veränderbarkeit des Zustands | Lokale Eingabe mit Rohbytes oder Hexdarstellung unter Linux x64; [Offline-EVM-Leitfaden](../guides/evm/evm-bytecode.md) |
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
@@ -172,6 +177,7 @@ REA benötigt Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) oder 26+ (>=26.12.1) so
| Paketerfassungen | Endpunkte, DNS, TLS SNI, Protokollverteilung und HTTP-Anfragen | Vom Aufrufer bereitgestellte tshark- und capinfos-Binaries; [pcap-Leitfaden](../guides/data/pcap-analysis.md) |
| .NET-Assemblies | Metadaten, CIL-Anweisungen, deklarierte native Abhängigkeiten und Build-Vergleiche | Statische Untersuchung; [Leitfaden für verwalteten Code](../guides/managed/managed-code-analysis.md) |
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
| Android-APKs | Manifest-Deklarationen, Klassen, dekompilierte Methoden und Verweise | JADX ohne grafische Oberfläche und ein vollständiges JDK unter Linux/macOS/Windows x64; [Android-Leitfaden](../guides/android/android-analysis.md) |
| Android-Geräte | Geräte, Pakete, Prozesse, Logs, Dumps, Bildschirmaufnahmen sowie APK- und Dateiübertragungen | Vom Aufrufer bereitgestelltes adb (Emulator oder Gerät); [ADB-Leitfaden](../guides/android/adb-device-analysis.md) |
| JEB-Projekte | Engine-gestützte Projekteinheiten, Artefakt-Prüfsummen und Pseudokode von Typen/Methoden | Ein vom Aufrufer gestarteter JEB-Client mit MCP, ausgewählt über REA_JEB_MCP_URL; [JEB-Leitfaden](../providers/jeb-analysis.md) |
@@ -273,6 +279,12 @@ REA exportiert eine lauffähige Umgebung mit einem einfachen Test, der prüft, o
[Umgebungsreferenz](../agent-environments.md) ·
[Demo auf X ansehen](https://x.com/reatools/status/2112574822584918075?s=20)
### Desktop-App-Umgebungen
REA kann auch eine Umgebung für eine Linux-Desktop-App erstellen, die ein Agent über Screenshots, Maus und Tastatur bedient. Aus einer einzeiligen Anfrage wie „Erstelle mir eine Gnote-Umgebung, in der der Agent der Einkaufslisten-Notiz Olivenöl hinzufügt“ installiert dein Agent die App auf einem lokalen Build-Computer, schreibt die Aufgabe, exportiert die Umgebung und prüft die Aufgabe auf einem frischen Computer. Der Rechner, der sie erstellt, braucht Linux auf amd64 oder arm64, Docker und die Version des agentenv-Frameworks, die der Leitfaden festlegt.
[Desktop-App-Umgebungen einrichten](../desktop-build-computer.md)
## Häufige Fragen
<details>
+13 -1
View File
@@ -1,6 +1,6 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md) · **Ελληνικά** · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md) · **Ελληνικά** · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
# REA: Reverse Engineer Anything
@@ -86,6 +86,10 @@ npx rea-agents setup
Το MCP χρησιμοποιεί συμπαγή σχήματα εισόδου από προεπιλογή. Για πλήρεις οδηγίες πεδίων και ένθετης επικύρωσης, όρισε `REA_MCP_INPUT_SCHEMA_PROFILE=full` στην καταχώριση MCP. Και τα δύο προφίλ διατηρούν όλα τα εργαλεία και την ίδια κανονική επικύρωση διακομιστή· δες τον οδηγό συμβολαίων MCP.
Η εγκατάσταση καταχωρίζει απευθείας τον επιλεγμένο runtime και το αρχικό script του REA. Αν χρησιμοποιείς package runner, διατήρησε την καταχώριση cache και τον runtime· απόκτησε το πακέτο από έμπιστο κατάλογο έξω από το έργο-στόχο. Δες τον οδηγό εγκατάστασης.
Τα πλήρη σχήματα εξόδου ανακοινώνονται από προεπιλογή. Αν ο client περιορίζει το `tools/list`, όρισε `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` ή `off` στην καταχώριση MCP. Η επικύρωση του διακομιστή και τα δομημένα αποτελέσματα παραμένουν πλήρη. Δες το «Output schemas» στον οδηγό συμβάσεων MCP.
### Ζήτησε από τον agent σου
```text
@@ -159,6 +163,7 @@ npx rea-agents@latest setup
| Δυαδικά αρχεία Rust | Ενσωματωμένα ονόματα, εκδόσεις, πηγές και σχέσεις εξάρτησης των crates από το cargo-auditable | Ενσωματωμένη στατική εξέταση ELF/PE/thin Mach-O· [δυαδικά αρχεία Rust](../rust-binaries.md) |
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
| Binary hardening | PIE, NX, RELRO, CFG and related header flags for ELF, PE and Mach-O | Built-in static header inspection; [binary hardening](../binary-hardening.md) |
| Apple IPS crashes | .ips metadata, threads, images, registers and crash classes | Built-in static JSON inspection; [Apple IPS](../apple-ips.md) |
@@ -174,6 +179,7 @@ npx rea-agents@latest setup
| Αποθηκευμένες καταγραφές δικτύου | Αιτήματα, αποκρίσεις, διαθέσιμα δεδομένα φορτίου και θέσεις στην πηγή | HAR ή SAZ του Fiddler Everywhere· mitmdump σε Linux για την εγγενή μορφή mitmproxy· [οδηγός καταγραφών](../guides/web/web-network-captures.md) |
| Assemblies .NET | Μεταδεδομένα, εντολές CIL, δηλωμένες εξαρτήσεις από κώδικα μηχανής και συγκρίσεις builds | Καμία πρόσθετη απαίτηση (μόνο στατική ανάλυση)· [οδηγός διαχειριζόμενου κώδικα](../guides/managed/managed-code-analysis.md) |
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
| APK Android | Δηλώσεις manifest, κλάσεις, απομεταγλωττισμένες μέθοδοι και αναφορές | JADX χωρίς γραφικό περιβάλλον και πλήρες JDK σε Linux/macOS/Windows x64· [οδηγός Android](../guides/android/android-analysis.md) |
| Συσκευές Android | Συσκευές, πακέτα, διεργασίες, logs, dumps, στιγμιότυπα οθόνης και μεταφορές APK/αρχείων | adb που παρέχει ο χρήστης (εξομοιωτής ή φυσική συσκευή)· [οδηγός ADB](../guides/android/adb-device-analysis.md) |
| Έργα JEB | Μονάδες έργου από τη μηχανή ανάλυσης, ψηφιακά αποτυπώματα αρχείων και ψευδοκώδικα τύπων/μεθόδων | Client JEB που έχει ξεκινήσει ο χρήστης και παρέχει MCP, επιλεγμένος μέσω REA_JEB_MCP_URL· [οδηγός JEB](../providers/jeb-analysis.md) |
@@ -275,6 +281,12 @@ agent-env run ./my-env
[Αναφορά περιβαλλόντων](../agent-environments.md) ·
[Δείτε το demo στο X](https://x.com/reatools/status/2112574822584918075?s=20)
### Περιβάλλοντα εφαρμογών επιφάνειας εργασίας
Το REA μπορεί επίσης να δημιουργήσει περιβάλλον για μια εφαρμογή επιφάνειας εργασίας Linux, την οποία ο πράκτορας χρησιμοποιεί μέσω στιγμιότυπων οθόνης, ποντικιού και πληκτρολογίου. Από ένα αίτημα μίας γραμμής, όπως «Φτιάξε μου ένα περιβάλλον Gnote όπου ο πράκτορας προσθέτει ελαιόλαδο στη σημείωση με τη λίστα αγορών», ο πράκτοράς σας εγκαθιστά την εφαρμογή σε έναν τοπικό υπολογιστή κατασκευής, γράφει την εργασία, εξάγει το περιβάλλον και ελέγχει την εργασία σε έναν νέο υπολογιστή. Ο υπολογιστής που το κατασκευάζει χρειάζεται Linux σε amd64 ή arm64, Docker και την έκδοση του πλαισίου agentenv που ορίζει ο οδηγός.
[Ρύθμιση περιβαλλόντων εφαρμογών επιφάνειας εργασίας](../desktop-build-computer.md)
## Συχνές ερωτήσεις
<details>
+13 -1
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · **Español** · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
# REA: Ingeniería inversa de cualquier cosa
@@ -84,6 +84,10 @@ La configuración admite Claude Code, Codex, Cursor, Gemini CLI, Grok Build y [o
MCP usa esquemas de entrada compactos por defecto. Para ver todas las instrucciones de campos y la validación anidada, establece `REA_MCP_INPUT_SCHEMA_PROFILE=full` en el registro MCP. Ambos perfiles conservan todas las herramientas y la misma validación canónica del servidor; consulta la guía de contratos MCP.
La configuración registra directamente el entorno de ejecución elegido y el script de entrada de REA. Si usas un ejecutor de paquetes, conserva su entrada de caché y el entorno de ejecución; descarga el paquete desde un directorio de confianza fuera del proyecto objetivo. Consulta la guía de instalación.
Los esquemas de salida completos se anuncian por defecto. Si tu cliente limita `tools/list`, establece `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` o `off` en el registro MCP. La validación del servidor y los resultados estructurados siguen siendo completos. Consulta «Output schemas» en la guía de contratos MCP.
### Pregunta a tu agente
```text
@@ -157,6 +161,7 @@ REA requiere Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) o 26+ (>=26.12.1), adem
| Estructura ELF sin ejecutar | Secciones, segmentos, símbolos/reubicaciones originales y posibles medidas de mitigación detectadas mediante análisis estático | pwntools proporcionado por quien llama, en Linux x64; [diagnóstico de binarios](../guides/native/binary-diagnostics.md) |
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
| Bytecode EVM | Selectores de despacho, desplazamientos en bytes, argumentos inferidos y mutabilidad | Entrada local con bytes sin procesar o representación hexadecimal, en Linux x64; [guía de EVM sin ejecutar](../guides/evm/evm-bytecode.md) |
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
@@ -172,6 +177,7 @@ REA requiere Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) o 26+ (>=26.12.1), adem
| Capturas de paquetes | Endpoints, DNS, TLS SNI, distribución de protocolos y solicitudes HTTP | tshark y capinfos suministrados por el autor de la llamada; [guía pcap](../guides/data/pcap-analysis.md) |
| Ensamblados .NET | Metadatos, instrucciones CIL, dependencias nativas declaradas y comparaciones de compilaciones | Inspección estática; [guía de código administrado](../guides/managed/managed-code-analysis.md) |
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
| APK de Android | Declaraciones del manifiesto, clases, métodos descompilados y referencias | JADX sin interfaz gráfica y un JDK completo en Linux/macOS/Windows x64; [guía de Android](../guides/android/android-analysis.md) |
| Dispositivos Android | Dispositivos, paquetes, procesos, registros, volcados, capturas de pantalla y transferencias de APK/archivos | adb suministrado por el autor de la llamada (emulador o dispositivo); [guía de ADB](../guides/android/adb-device-analysis.md) |
| Proyectos JEB | Unidades de proyecto del motor, resúmenes de artefactos y pseudocódigo de tipos/métodos | Un cliente JEB iniciado por el autor de la llamada que sirve MCP, seleccionado con REA_JEB_MCP_URL; [guía de JEB](../providers/jeb-analysis.md) |
@@ -273,6 +279,12 @@ REA exporta un entorno ejecutable con una prueba básica que comprueba que arran
[Referencia de entornos](../agent-environments.md) ·
[Ver la demo en X](https://x.com/reatools/status/2112574822584918075?s=20)
### Entornos de aplicaciones de escritorio
REA también puede crear un entorno de una aplicación de escritorio de Linux, que un agente usa mediante capturas de pantalla, el ratón y el teclado. A partir de una petición de una línea, como «Créame un entorno de Gnote en el que el agente añada aceite de oliva a la nota de la lista de la compra», tu agente instala la aplicación en un ordenador de compilación local, escribe la tarea, exporta el entorno y comprueba la tarea en un ordenador nuevo. El equipo que lo crea necesita Linux en amd64 o arm64, Docker y la versión del framework agentenv que fija la guía.
[Configurar entornos de aplicaciones de escritorio](../desktop-build-computer.md)
## Preguntas frecuentes
<details>
+13 -1
View File
@@ -1,7 +1,7 @@
<div align="center" dir="rtl">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · **فارسی** · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
# REA: مهندسی معکوس هر چیزی
@@ -76,6 +76,10 @@ npx rea-agents setup
MCP به‌طور پیش‌فرض از schema ورودی فشرده استفاده می‌کند. برای راهنمای کامل فیلدها و اعتبارسنجی تو‌در‌تو، در ثبت MCP مقدار `REA_MCP_INPUT_SCHEMA_PROFILE=full` را تنظیم کنید. هر دو حالت همهٔ ابزارها و اعتبارسنجی استاندارد یکسان سرور را نگه می‌دارند؛ راهنمای قراردادهای MCP را ببینید.
راه‌اندازی، محیط اجرای انتخاب‌شده و اسکریپت ورودی REA را مستقیماً ثبت می‌کند. اگر از اجراکنندهٔ بسته استفاده می‌کنید، ورودی حافظهٔ پنهان و محیط اجرا را حفظ کنید؛ بسته را از پوشه‌ای قابل اعتماد خارج از پروژهٔ هدف دریافت کنید. راهنمای نصب را ببینید.
طرح‌های خروجی کامل به‌طور پیش‌فرض اعلام می‌شوند. اگر کلاینت `tools/list` را محدود می‌کند، در ثبت MCP مقدار `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` یا `off` را تنظیم کنید. اعتبارسنجی سرور و نتایج ساخت‌یافته کامل می‌مانند. بخش «Output schemas» در راهنمای قراردادهای MCP را ببینید.
### از ایجنت خود بپرسید
```text
@@ -149,6 +153,7 @@ REA به Node.js 22.x (>=22.23.4)، 24.x (>=24.22.1) یا 26+ (>=26.12.1)، به
| ساختار ELF آفلاین | بخش‌ها، سگمنت‌ها، نمادها و relocationهای اصلی و گزینه‌های احتمالی کاهش آسیب‌پذیری ایستا | pwntools تأمین‌شده توسط فراخواننده روی Linux x64؛ [تشخیص باینری](../guides/native/binary-diagnostics.md) |
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
| بایت‌کد EVM | selectorهای dispatch، offsetهای بایتی، آرگومان‌های استنباط‌شده و قابلیت تغییر وضعیت | دادهٔ خام/hex محلی روی Linux x64؛ [راهنمای EVM آفلاین](../guides/evm/evm-bytecode.md) |
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
@@ -163,6 +168,7 @@ REA به Node.js 22.x (>=22.23.4)، 24.x (>=24.22.1) یا 26+ (>=26.12.1)، به
| داده‌های ضبط‌شدهٔ شبکه | درخواست‌ها، پاسخ‌ها، payloadهای آشکارشده و مکان آن‌ها در منبع | HAR / Fiddler Everywhere SAZ؛ ابزار mitmdump در لینوکس برای ضبط‌های بومی mitmproxy؛ [راهنمای ضبط شبکه](../guides/web/web-network-captures.md) |
| اسمبلی‌های .NET | فراداده، دستورالعمل‌های CIL، وابستگی‌های بومی اعلام‌شده و مقایسهٔ buildها | بررسی ایستا؛ [راهنمای کد مدیریت‌شده](../guides/managed/managed-code-analysis.md) |
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
| فایل‌های APK اندروید | تعاریف Manifest، کلاس‌ها، متدهای دیکامپایل‌شده و ارجاعات | JADX بدون رابط گرافیکی و JDK کامل در Linux/macOS/Windows x64؛ [راهنمای اندروید](../guides/android/android-analysis.md) |
| دستگاه‌های اندروید | دستگاه‌ها، بسته‌ها، فرایندها، لاگ‌ها، دامپ‌ها، اسکرین‌شات‌ها و انتقال APK/فایل | adb تأمین‌شده توسط فراخوان‌کننده (شبیه‌ساز یا دستگاه)؛ [راهنمای ADB](../guides/android/adb-device-analysis.md) |
| پروژه‌های JEB | واحدهای پروژه از موتور، هش‌های مصنوع و شبه‌کدِ نوع/متد | یک کلاینت JEB که توسط فراخوان‌کننده اجرا شده و MCP ارائه می‌دهد و با REA_JEB_MCP_URL انتخاب می‌شود؛ [راهنمای JEB](../providers/jeb-analysis.md) |
@@ -265,6 +271,12 @@ REA محیطی آمادهٔ اجرا همراه با یک آزمون ساده ب
[مرجع محیط‌ها](../agent-environments.md) ·
[نمایش را در X ببینید](https://x.com/reatools/status/2112574822584918075?s=20)
### محیط‌های برنامه‌های دسکتاپ
REA می‌تواند برای یک برنامهٔ دسکتاپ Linux هم محیط بسازد که عامل با تصویر صفحه، ماوس و صفحه‌کلید از آن استفاده می‌کند. از یک درخواست یک‌خطی، مثل «یک محیط Gnote برایم بساز که در آن عامل روغن زیتون را به یادداشت فهرست خرید اضافه کند»، عامل شما برنامه را روی یک رایانهٔ ساخت محلی نصب می‌کند، کار را می‌نویسد، محیط را صادر می‌کند و کار را روی یک رایانهٔ تازه بررسی می‌کند. دستگاهی که آن را می‌سازد به Linux روی amd64 یا arm64، Docker و نسخه‌ای از چارچوب agentenv که راهنما تعیین کرده نیاز دارد.
[راه‌اندازی محیط‌های برنامه‌های دسکتاپ](../desktop-build-computer.md)
## پرسش‌های متداول
<details><summary><strong>کدام ایجنت‌ها می‌توانند از REA استفاده کنند؟</strong></summary>
+13 -1
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · **Français** · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
# REA : rétro-ingénierie de tout
@@ -84,6 +84,10 @@ Setup prend en charge Claude Code, Codex, Cursor, Gemini CLI, Grok Build et [d'a
MCP utilise par défaut des schémas d’entrée compacts. Pour les descriptions complètes des champs et de la validation imbriquée, définissez `REA_MCP_INPUT_SCHEMA_PROFILE=full` dans l’enregistrement MCP. Les deux profils conservent tous les outils et la même validation canonique du serveur ; voir le guide des contrats MCP.
La configuration enregistre directement le runtime choisi et le script d’entrée de REA. Avec un exécuteur de paquets, conservez son entrée de cache et le runtime ; récupérez le paquet depuis un répertoire de confiance hors du projet cible. Consultez le guide d’installation.
Les schémas de sortie complets sont annoncés par défaut. Si votre client limite `tools/list`, définissez `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` ou `off` dans l’enregistrement MCP. La validation du serveur et les résultats structurés restent complets. Consultez « Output schemas » dans le guide des contrats MCP.
### Interroger votre agent
```text
@@ -156,6 +160,7 @@ REA nécessite Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) ou 26+ (>=26.12.1), ai
| Structure ELF hors ligne | Sections, segments, symboles et relocations d'origine, et protections statiques candidates | pwntools fourni par l'utilisateur sous Linux x64 ; [diagnostics binaires](../guides/native/binary-diagnostics.md) |
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
| Artefact WASM | Validation, sections, formes WAT exactes d'import/export et WAT décodé | WABT 1.0.42 fourni par l'utilisateur ; `inspect_wasm_artifact` |
| Bytecode EVM | Sélecteurs de dispatch, offsets en octets, arguments inférés et mutabilité | Fichier local brut ou hexadécimal sous Linux x64 ; [guide EVM hors ligne](../guides/evm/evm-bytecode.md) |
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
@@ -172,6 +177,7 @@ REA nécessite Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) ou 26+ (>=26.12.1), ai
| Captures de paquets | Points de terminaison, DNS, TLS SNI, distribution des protocoles et requêtes HTTP | tshark et capinfos fournis par l'appelant ; [guide pcap](../guides/data/pcap-analysis.md) |
| Assemblys .NET | Métadonnées, instructions CIL, dépendances natives déclarées et comparaisons de builds | Inspection statique ; [guide du code managé](../guides/managed/managed-code-analysis.md) |
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
| APK Android | Déclarations du manifeste, classes, méthodes décompilées et références | JADX headless et un JDK complet sous Linux/macOS/Windows x64 ; [guide Android](../guides/android/android-analysis.md) |
| Appareils Android | Appareils, paquets, processus, journaux, dumps, captures d'écran et transferts d'APK/fichiers | adb fourni par l'appelant (émulateur ou appareil) ; [guide ADB](../guides/android/adb-device-analysis.md) |
| Projets JEB | Unités de projet fournies par le moteur, condensés d'artefacts et pseudo-code de types/méthodes | Un client JEB démarré par l'appelant servant MCP, sélectionné via REA_JEB_MCP_URL ; [guide JEB](../providers/jeb-analysis.md) |
@@ -270,6 +276,12 @@ REA exporte un environnement exécutable avec un test de base qui vérifie qu’
[Référence des environnements](../agent-environments.md) ·
[Voir la démo sur X](https://x.com/reatools/status/2112574822584918075?s=20)
### Environnements d’applications de bureau
REA peut aussi créer un environnement pour une application de bureau Linux, qu’un agent utilise par captures d’écran, souris et clavier. À partir d’une demande d’une ligne, comme « Crée-moi un environnement Gnote où l’agent ajoute de l’huile d’olive à la note de liste de courses », votre agent installe l’application sur un ordinateur de construction local, rédige la tâche, exporte l’environnement et vérifie la tâche sur un ordinateur neuf. La machine qui le construit a besoin de Linux sur amd64 ou arm64, de Docker et de la version du framework agentenv fixée par le guide.
[Configurer les environnements d’applications de bureau](../desktop-build-computer.md)
## Questions fréquentes
<details>
+13 -1
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · **Bahasa Indonesia** · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
# REA: Rekayasa Balik Apa Pun
@@ -84,6 +84,10 @@ Penyiapan mendukung Claude Code, Codex, Cursor, Gemini CLI, Grok Build, dan [age
MCP menggunakan skema input ringkas secara default. Untuk petunjuk bidang lengkap dan validasi bertingkat, atur `REA_MCP_INPUT_SCHEMA_PROFILE=full` pada pendaftaran MCP. Kedua profil mempertahankan semua alat dan validasi server kanonis yang sama; lihat panduan kontrak MCP.
Setup mencatat runtime yang dipilih dan skrip masuk REA secara langsung. Jika memakai package runner, pertahankan entri cache dan runtime tersebut; unduh paket dari direktori tepercaya di luar proyek target. Lihat panduan instalasi.
Skema keluaran lengkap diumumkan secara default. Jika klien membatasi `tools/list`, atur `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` atau `off` dalam registrasi MCP. Validasi server dan hasil terstruktur tetap lengkap. Lihat «Output schemas» di panduan kontrak MCP.
### Minta agen Anda
```text
@@ -159,6 +163,7 @@ Alat tambahan dan dukungan sistem host bergantung pada target yang dianalisis:
| Tata letak ELF offline | Bagian, segmen, simbol/relokasi asli, dan kandidat mitigasi statis | pwntools yang disediakan pemanggil pada Linux x64; [diagnostik biner](../guides/native/binary-diagnostics.md) |
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
| Artefak WASM | Validasi, bagian, bentuk WAT import/ekspor yang tepat, dan WAT yang didekode | WABT 1.0.42 yang disediakan pemanggil; `inspect_wasm_artifact` |
| Bytecode EVM | Selector dispatch, offset byte, argumen yang disimpulkan, dan sifat mutabilitas | Pembawa data raw/hex lokal di Linux x64; [panduan EVM offline](../guides/evm/evm-bytecode.md) |
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
@@ -175,6 +180,7 @@ Alat tambahan dan dukungan sistem host bergantung pada target yang dianalisis:
| Capturan paket | Endpoint, DNS, TLS SNI, distribusi protokol, dan permintaan HTTP | tshark dan capinfos buatan pemanggil; [panduan pcap](../guides/data/pcap-analysis.md) |
| Assembly .NET | Metadata, instruksi CIL, dependensi native yang dideklarasikan, dan perbandingan build | Tidak ada (hanya analisis statis); [panduan kode terkelola](../guides/managed/managed-code-analysis.md) |
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
| APK Android | Deklarasi manifest, kelas, metode hasil dekompilasi, dan referensi | JADX mode headless dan JDK lengkap di Linux/macOS/Windows x64; [panduan Android](../guides/android/android-analysis.md) |
| Perangkat Android | Perangkat, paket, proses, log, dump, tangkapan layar, serta transfer APK/berkas | adb buatan pemanggil (emulator atau perangkat); [panduan ADB](../guides/android/adb-device-analysis.md) |
| Proyek JEB | Unit proyek bertenaga mesin, hash artefak, dan pseudokode tipe/metode | Klien JEB yang dijalankan pemanggil dan menyajikan MCP, dipilih dengan REA_JEB_MCP_URL; [panduan JEB](../providers/jeb-analysis.md) |
@@ -281,6 +287,12 @@ REA mengekspor lingkungan yang dapat dijalankan dengan uji dasar untuk memeriksa
[Referensi lingkungan](../agent-environments.md) ·
[Tonton demo di X](https://x.com/reatools/status/2112574822584918075?s=20)
### Lingkungan aplikasi desktop
REA juga dapat membuat lingkungan untuk aplikasi desktop Linux yang digunakan agen melalui tangkapan layar, mouse, dan keyboard. Dari permintaan satu baris, seperti "Buatkan lingkungan Gnote tempat agen menambahkan minyak zaitun ke catatan daftar belanja", agen Anda memasang aplikasi di komputer build lokal, menulis tugas, mengekspor lingkungan, dan memeriksa tugas di komputer baru. Mesin yang membuatnya memerlukan Linux di amd64 atau arm64, Docker, dan versi framework agentenv yang ditetapkan panduan.
[Siapkan lingkungan aplikasi desktop](../desktop-build-computer.md)
## FAQ
<details>
+13 -1
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · **Italiano**
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
# REA: Reverse Engineer Anything
@@ -84,6 +84,10 @@ La configurazione supporta Claude Code, Codex, Cursor, Gemini CLI, Grok Build e
MCP usa schemi di input compatti per impostazione predefinita. Per tutte le indicazioni sui campi e la validazione annidata, imposta `REA_MCP_INPUT_SCHEMA_PROFILE=full` nella registrazione MCP. Entrambi i profili mantengono tutti gli strumenti e la stessa validazione canonica del server; vedi la guida ai contratti MCP.
La configurazione registra direttamente il runtime scelto e lo script di avvio di REA. Se usi un package runner, conserva la sua voce nella cache e il runtime; scarica il pacchetto da una directory attendibile fuori dal progetto di destinazione. Consulta la guida di installazione.
Gli schemi di output completi sono dichiarati per impostazione predefinita. Se il client limita `tools/list`, imposta `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` o `off` nella registrazione MCP. La validazione del server e i risultati strutturati restano completi. Consulta «Output schemas» nella guida ai contratti MCP.
### Chiedi al tuo agente
```text
@@ -156,6 +160,7 @@ REA richiede Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) o 26+ (>=26.12.1), oltre
| Layout ELF offline | Sezioni, segmenti, simboli/relocazioni originali e candidati mitigazioni statiche | pwntools fornito dal chiamante su Linux x64; [diagnostica binaria](../guides/native/binary-diagnostics.md) |
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
| Artefatto WASM | Convalida, sezioni, forme WAT di import/export esatte e WAT decodificato | WABT 1.0.42 fornito dal chiamante; `inspect_wasm_artifact` |
| Bytecode EVM | Selettori di dispatch, offset dei byte, argomenti inferiti e mutabilità | Carrier raw/hex locale su Linux x64; [guida EVM offline](../guides/evm/evm-bytecode.md) |
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
@@ -172,6 +177,7 @@ REA richiede Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) o 26+ (>=26.12.1), oltre
| Captured di pacchetti | Endpoint, DNS, TLS SNI, distribuzione dei protocolli e richieste HTTP | tshark e capinfos forniti dal chiamante; [guida pcap](../guides/data/pcap-analysis.md) |
| Assembly .NET | Metadati, istruzioni CIL, dipendenze native dichiarate e confronti di build | Nessuno (solo statico); [guida managed-code](../guides/managed/managed-code-analysis.md) |
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
| APK Android | Dichiarazioni manifest, classi, metodi decompilati e riferimenti | JADX headless e un JDK completo su Linux/macOS/Windows x64; [guida Android](../guides/android/android-analysis.md) |
| Dispositivi Android | Dispositivi, pacchetti, processi, log, dump, screenshot e trasferimenti APK/file | adb fornito dal chiamante (emulatore o hardware); [guida ADB](../guides/android/adb-device-analysis.md) |
| Progetti JEB | Unità di progetto dal motore, digest degli artifact e pseudocodice di tipi/metodi | Client JEB avviato dal chiamante via MCP, selezionato con REA_JEB_MCP_URL; [guida JEB](../providers/jeb-analysis.md) |
@@ -270,6 +276,12 @@ REA esporta un ambiente eseguibile con un test di base che ne verifica l’avvio
[Riferimento degli ambienti](../agent-environments.md) ·
[Guarda la demo su X](https://x.com/reatools/status/2112574822584918075?s=20)
### Ambienti di app desktop
REA può creare anche un ambiente per un’app desktop Linux, che un agente usa tramite screenshot, mouse e tastiera. Da una richiesta di una riga, come «Creami un ambiente Gnote in cui l’agente aggiunge l’olio d’oliva alla nota della lista della spesa», il tuo agente installa l’app su un computer di build locale, scrive l’attività, esporta l’ambiente e verifica l’attività su un computer nuovo. La macchina che lo crea richiede Linux su amd64 o arm64, Docker e la versione del framework agentenv indicata dalla guida.
[Configurare gli ambienti di app desktop](../desktop-build-computer.md)
## FAQ
<details>
+13 -1
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · **日本語** · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
# REA:あらゆるものをリバースエンジニアリング
@@ -84,6 +84,10 @@ npx rea-agents setup
MCP は既定でコンパクトな入力スキーマを使用します。完全なフィールド説明と入れ子の検証情報が必要な場合は、MCP 登録に `REA_MCP_INPUT_SCHEMA_PROFILE=full` を設定してください。どちらも全ツールと同じ正規サーバー検証を維持します。詳細は MCP 契約ガイドを参照してください。
セットアップは選択したランタイムと REA のエントリースクリプトを直接登録します。パッケージランナーを使う場合は、そのキャッシュ項目とランタイムを残し、対象プロジェクト外の信頼できるディレクトリからパッケージを取得してください。 インストールガイドを参照してください。
出力スキーマはデフォルトで完全なものが公開されます。クライアントが `tools/list` を制限する場合は、MCP 登録で `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` または `off` を設定してください。サーバー側の検証と構造化結果は完全なままです。 MCP 契約ガイドの「Output schemas」を参照してください。
### エージェントに依頼する
```text
@@ -157,6 +161,7 @@ REA には Node.js 22.x(>=22.23.4)、24.x(>=24.22.1)、または 26+ (>=
| オフライン ELF レイアウト | セクション、セグメント、元のシンボル/再配置情報、静的解析によるセキュリティ対策の候補 | Linux x64 で利用者が用意する pwntools;[バイナリ診断](../guides/native/binary-diagnostics.md) |
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
| EVM バイトコード | ディスパッチセレクター、バイトオフセット、推定された引数と状態変更の可否 | Linux x64 上のローカルの生バイト/16 進数の入力ファイル;[オフライン EVM ガイド](../guides/evm/evm-bytecode.md) |
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
@@ -172,6 +177,7 @@ REA には Node.js 22.x(>=22.23.4)、24.x(>=24.22.1)、または 26+ (>=
| パケットキャプチャ | エンドポイント、DNS、TLS SNI、プロトコル分布、HTTPリクエスト | 呼び出し側が用意した tshark と capinfos;[pcapガイド](../guides/data/pcap-analysis.md) |
| .NET アセンブリ | メタデータ、CIL 命令、宣言されたネイティブ依存関係、ビルドの比較 | 静的な検査;[マネージドコードのガイド](../guides/managed/managed-code-analysis.md) |
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
| Android APK | マニフェストの宣言、クラス、逆コンパイルされたメソッド、参照 | Linux/macOS/Windows x64 上のヘッドレス JADX と完全な JDK;[Android ガイド](../guides/android/android-analysis.md) |
| Android デバイス | デバイス、パッケージ、プロセス、ログ、ダンプ、スクリーンキャプチャ、APK/ファイル転送 | 呼び出し側が用意した adb(エミュレーターまたは実機);[ADB ガイド](../guides/android/adb-device-analysis.md) |
| JEBプロジェクト | エンジンによるプロジェクトユニット、アーティファクトのダイジェスト、型/メソッドの擬似コード | 呼び出し側が起動し MCP を提供する JEB クライアント(REA_JEB_MCP_URL で選択);[JEB ガイド](../providers/jeb-analysis.md) |
@@ -275,6 +281,12 @@ REA は実行可能な環境と、起動して応答することを確認する
[環境リファレンス](../agent-environments.md) ·
[X でデモを見る](https://x.com/reatools/status/2112574822584918075?s=20)
### デスクトップアプリの環境
REA は、エージェントがスクリーンショット、マウス、キーボードで操作する Linux デスクトップアプリの環境も構築できます。「エージェントが買い物リストのメモにオリーブオイルを追加する Gnote 環境を作って」のような 1 行の依頼から、エージェントがローカルのビルド用コンピューターにアプリをインストールし、タスクを書き、環境をエクスポートし、新しいコンピューターでタスクを確認します。構築するマシンには、amd64 または arm64 の Linux、Docker、ガイドが指定するバージョンの agentenv フレームワークが必要です。
[デスクトップアプリ環境を設定する](../desktop-build-computer.md)
## よくある質問
<details>
+13 -1
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · **한국어** · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
# REA: 무엇이든 리버스 엔지니어링
@@ -84,6 +84,10 @@ npx rea-agents setup
MCP는 기본적으로 간결한 입력 스키마를 사용합니다. 전체 필드 안내와 중첩 검증 정보가 필요하면 MCP 등록에서 `REA_MCP_INPUT_SCHEMA_PROFILE=full`을 설정하세요. 두 프로필 모두 전체 도구와 동일한 정규 서버 검증을 유지합니다. MCP 계약 가이드를 참고하세요.
설정은 선택한 런타임과 REA 진입 스크립트를 직접 등록합니다. 패키지 실행기를 사용한다면 해당 캐시 항목과 런타임을 유지하고, 대상 프로젝트 밖의 신뢰할 수 있는 디렉터리에서 패키지를 받으세요. 설치 가이드를 참고하세요.
기본적으로 완전한 출력 스키마가 제공됩니다. 클라이언트가 `tools/list` 크기를 제한한다면 MCP 등록에서 `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` 또는 `off`로 설정하세요. 서버 검증과 구조화된 결과는 완전하게 유지됩니다. MCP 계약 가이드의 «Output schemas»를 참고하세요.
### 에이전트에게 요청
```text
@@ -159,6 +163,7 @@ REA에는 Node.js 22.x(>=22.23.4), 24.x(>=24.22.1) 또는 26+ (>=26.12.1)와 npm
| Rust 바이너리 | cargo-auditable이 내장한 크레이트 이름, 버전, 소스, 의존성 관계 | REA 내장 ELF/PE/thin Mach-O 정적 검사; [Rust 바이너리](../rust-binaries.md) |
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
| Binary hardening | PIE, NX, RELRO, CFG and related header flags for ELF, PE and Mach-O | Built-in static header inspection; [binary hardening](../binary-hardening.md) |
| Apple IPS crashes | .ips metadata, threads, images, registers and crash classes | Built-in static JSON inspection; [Apple IPS](../apple-ips.md) |
@@ -185,6 +190,7 @@ REA에는 Node.js 22.x(>=22.23.4), 24.x(>=24.22.1) 또는 26+ (>=26.12.1)와 npm
| 패키지 및 리소스 | 파일 목록, 다이제스트, plist, Apple 번들 구조, 추출한 리소스 | [아티팩트 및 JavaScript 가이드](../guides/javascript/javascript-artifact-reconstruction.md), [Apple 애플리케이션](../guides/apple/apple-application-analysis.md) |
| 프로세스 동작 | 터미널 출력, 상호작용, 종료 및 파일 시스템 관찰 결과, 실행 비교 | 네이티브 PTY를 지원하는 Linux/macOS; [프로세스 캡처](../guides/runtime/process-capture.md) |
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
| GPU 코드 객체 | CUDA/HIP 대상, 선택한 커널 매개변수와 자원, 보존된 PTX 텍스트 | 내장 정적 검사 ELF/PE/fatbin/CUBIN/PTX; [GPU](../gpu-code-objects.md) |
| 모델 파일 | GGUF / safetensors 메타데이터, 텐서 선언과 계산한 합계 | 헤더 검사; 전체 파일 해시는 선택 사항; [GGUF / safetensors](../model-artifacts.md) |
| IL2CPP 메타데이터 | Unity global-metadata.dat 어셈블리 이미지, 형식·메서드 이름과 인덱스 범위 | 버전 24, 27, 29, 31, 39 정적 디코딩; Unity 불필요 |
@@ -273,6 +279,12 @@ REA는 실행 가능한 환경과 시작 및 응답 여부를 확인하는 기
[환경 참조 문서](../agent-environments.md) ·
[X에서 데모 보기](https://x.com/reatools/status/2112574822584918075?s=20)
### 데스크톱 앱 환경
REA는 에이전트가 스크린샷, 마우스, 키보드로 사용하는 Linux 데스크톱 앱의 환경도 만들 수 있습니다. "에이전트가 장보기 목록 메모에 올리브유를 추가하는 Gnote 환경을 만들어 줘" 같은 한 줄 요청에서 에이전트가 로컬 빌드 컴퓨터에 앱을 설치하고, 작업을 작성하고, 환경을 내보낸 뒤 새 컴퓨터에서 작업을 확인합니다. 환경을 만드는 머신에는 amd64 또는 arm64의 Linux, Docker, 가이드가 지정한 버전의 agentenv 프레임워크가 필요합니다.
[데스크톱 앱 환경 설정하기](../desktop-build-computer.md)
## 자주 묻는 질문
<details>
+13 -1
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · **മലയാളം** · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
· [Ελληνικά](README_el.md) · **മലയാളം** · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
# REA: എന്തും Reverse Engineer ചെയ്യുക
@@ -86,6 +86,10 @@ Claude Code, Codex, Cursor, Gemini CLI, Grok Build, കൂടാതെ [മറ
MCP സാധാരണയായി compact input schemas ഉപയോഗിക്കുന്നു. പൂർണ്ണ field guidance-ഉം nested validation details-ഉം വേണമെങ്കിൽ MCP registration-ൽ `REA_MCP_INPUT_SCHEMA_PROFILE=full` സജ്ജമാക്കുക. രണ്ടു profiles-ലും എല്ലാ tools-ഉം ഒരേ canonical server validation-ഉം നിലനിൽക്കും; MCP contracts guide കാണുക.
തിരഞ്ഞെടുത്ത runtime-ഉം REA entry script-ഉം setup നേരിട്ട് രജിസ്റ്റർ ചെയ്യുന്നു. Package runner ഉപയോഗിക്കുമ്പോൾ അതിന്റെ cache entry-യും runtime-ഉം നിലനിർത്തുക; target project-ന് പുറത്തുള്ള വിശ്വസനീയമായ ഡയറക്ടറിയിൽ നിന്ന് package നേടുക. ഇൻസ്റ്റലേഷൻ ഗൈഡ് കാണുക.
പൂർണ്ണ output schema-കൾ സ്ഥിരസ്ഥിതിയായി പരസ്യപ്പെടുത്തുന്നു. Client `tools/list` പരിമിതപ്പെടുത്തുന്നുവെങ്കിൽ MCP registration-ൽ `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` അല്ലെങ്കിൽ `off` സജ്ജമാക്കുക. Server validation-ഉം structured result-കളും പൂർണ്ണമായി നിലനിൽക്കും. MCP കരാർ ഗൈഡിലെ «Output schemas» കാണുക.
### നിങ്ങളുടെ agent-നോട് ആവശ്യപ്പെടുക
```text
@@ -159,6 +163,7 @@ REA-യ്ക്ക് Node.js 22.x (>=22.23.4), 24.x (>=24.22.1), അല്ല
| Rust binaries | ഉൾച്ചേർത്ത cargo-auditable crate പേരുകൾ, versions, sources, dependency edges | Built-in static ELF/PE/thin Mach-O പരിശോധന; [Rust binaries](../rust-binaries.md) |
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
| Binary hardening | PIE, NX, RELRO, CFG and related header flags for ELF, PE and Mach-O | Built-in static header inspection; [binary hardening](../binary-hardening.md) |
| Linux kernel modules | .modinfo keys, __versions CRCs, this_module presence, and signature trailer | Built-in static ELF inspection; [kernel modules](../kernel-modules.md) |
@@ -174,6 +179,7 @@ REA-യ്ക്ക് Node.js 22.x (>=22.23.4), 24.x (>=24.22.1), അല്ല
| Saved network captures | Requests, responses, പുറത്തുകാണുന്ന payload-ുകൾ, source locations | HAR അല്ലെങ്കിൽ Fiddler Everywhere SAZ; native mitmproxy-നായി Linux-ൽ mitmdump; [capture guide](../guides/web/web-network-captures.md) |
| .NET assemblies | Metadata, CIL instructions, പ്രഖ്യാപിച്ച native dependencies, build comparisons | ഒന്നും ആവശ്യമില്ല (static മാത്രം); [managed-code guide](../guides/managed/managed-code-analysis.md) |
| Python packaged apps | CArchive/PYZ entries, Python version, bytecode, resources and runtime options | Static PyInstaller parsing; [Python guide](../python-packaged-applications.md) |
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
| Android APKs | Manifest declarations, classes, decompiled methods, references | Linux/macOS/Windows x64-ൽ Headless JADX-ഉം full JDK-ഉം; [Android guide](../guides/android/android-analysis.md) |
| Android devices | Devices, packages, processes, logs, dumps, screen captures, APK/file transfers | Caller നൽകുന്ന adb (emulator അല്ലെങ്കിൽ hardware); [ADB guide](../guides/android/adb-device-analysis.md) |
| JEB projects | Engine-backed project units, artifact digests, type/method pseudo-code | MCP സേവനം നൽകുന്ന caller ആരംഭിച്ച JEB client; REA_JEB_MCP_URL ഉപയോഗിച്ച് തിരഞ്ഞെടുക്കുക; [JEB guide](../providers/jeb-analysis.md) |
@@ -277,6 +283,12 @@ agent-env run ./my-env
[പരിതസ്ഥിതി റഫറൻസ്](../agent-environments.md) ·
[X-ൽ ഡെമോ കാണുക](https://x.com/reatools/status/2112574822584918075?s=20)
### ഡെസ്‌ക്‌ടോപ്പ് ആപ്പ് പരിതസ്ഥിതികൾ
സ്ക്രീൻഷോട്ടുകൾ, മൗസ്, കീബോർഡ് എന്നിവ വഴി ഏജന്റ് ഉപയോഗിക്കുന്ന Linux ഡെസ്‌ക്‌ടോപ്പ് ആപ്പിന്റെ പരിതസ്ഥിതിയും REA-യ്ക്ക് നിർമ്മിക്കാം. "ഷോപ്പിംഗ് ലിസ്റ്റ് നോട്ടിൽ ഏജന്റ് ഒലിവ് ഓയിൽ ചേർക്കുന്ന ഒരു Gnote പരിതസ്ഥിതി നിർമ്മിക്കുക" പോലുള്ള ഒറ്റവരി അഭ്യർത്ഥനയിൽ നിന്ന്, നിങ്ങളുടെ ഏജന്റ് ഒരു പ്രാദേശിക ബിൽഡ് കമ്പ്യൂട്ടറിൽ ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്യുന്നു, ടാസ്‌ക് എഴുതുന്നു, പരിതസ്ഥിതി എക്‌സ്‌പോർട്ട് ചെയ്യുന്നു, ഒരു പുതിയ കമ്പ്യൂട്ടറിൽ ടാസ്‌ക് പരിശോധിക്കുന്നു. ഇത് നിർമ്മിക്കുന്ന മെഷീന് amd64 അല്ലെങ്കിൽ arm64-ലെ Linux, Docker, ഗൈഡ് നിശ്ചയിക്കുന്ന agentenv ഫ്രെയിംവർക്ക് പതിപ്പ് എന്നിവ വേണം.
[ഡെസ്‌ക്‌ടോപ്പ് ആപ്പ് പരിതസ്ഥിതികൾ സജ്ജീകരിക്കുക](../desktop-build-computer.md)
## പതിവുചോദ്യങ്ങൾ
<details>
+13 -1
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · **Polski** · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
# REA: Reverse Engineer Anything
@@ -84,6 +84,10 @@ Konfigurator obsługuje Claude Code, Codex, Cursor, Gemini CLI, Grok Build i [in
MCP domyślnie używa zwartych schematów wejściowych. Pełne opisy pól i zagnieżdżonej walidacji włącza `REA_MCP_INPUT_SCHEMA_PROFILE=full` w rejestracji MCP. Oba profile zachowują wszystkie narzędzia i tę samą kanoniczną walidację serwera; zobacz przewodnik kontraktów MCP.
Konfiguracja zapisuje bezpośrednio wybrane środowisko uruchomieniowe i skrypt wejściowy REA. Przy użyciu narzędzia uruchamiającego pakiety zachowaj jego wpis w pamięci podręcznej i środowisko; pobierz pakiet z zaufanego katalogu poza projektem docelowym. Zobacz instrukcję instalacji.
Pełne schematy wyjściowe są udostępniane domyślnie. Jeśli klient ogranicza `tools/list`, ustaw `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` lub `off` w rejestracji MCP. Walidacja serwera i wyniki strukturalne pozostają pełne. Zobacz „Output schemas” w przewodniku po kontraktach MCP.
### Zapytaj agenta
```text
@@ -157,6 +161,7 @@ REA wymaga Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) lub 26+ (>=26.12.1) oraz n
| Układ pliku ELF w trybie offline | Sekcje, segmenty, oryginalne symbole/relokacje i potencjalne mechanizmy zabezpieczeń wskazane przez analizę statyczną | pwntools dostarczone przez użytkownika w systemie Linux x64; [diagnostyka plików binarnych](../guides/native/binary-diagnostics.md) |
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
| Kod bajtowy EVM | Selektory wywołań, przesunięcia bajtowe, wywnioskowane argumenty i mutowalność | Lokalny plik z surowymi bajtami lub zapisem szesnastkowym w systemie Linux x64; [przewodnik EVM offline](../guides/evm/evm-bytecode.md) |
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
@@ -172,6 +177,7 @@ REA wymaga Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) lub 26+ (>=26.12.1) oraz n
| Przechwytywanie pakietów | Punkty końcowe, DNS, TLS SNI, dystrybucja protokołów i żądania HTTP | Dostarczone przez wywołującego tshark i capinfos; [przewodnik pcap](../guides/data/pcap-analysis.md) |
| Zestawy .NET | Metadane, instrukcje CIL, zadeklarowane zależności natywne i porównania kompilacji | Analiza statyczna; [przewodnik kodu zarządzanego](../guides/managed/managed-code-analysis.md) |
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
| Pakiety APK dla Androida | Deklaracje manifestu, klasy, zdekompilowane metody i odwołania | JADX bez interfejsu graficznego i pełny JDK w systemach Linux/macOS/Windows x64; [przewodnik Androida](../guides/android/android-analysis.md) |
| Urządzenia z Androidem | Urządzenia, pakiety, procesy, logi, zrzuty, zrzuty ekranu oraz transfery APK/plików | adb dostarczony przez wywołującego (emulator lub urządzenie); [przewodnik ADB](../guides/android/adb-device-analysis.md) |
| Projekty JEB | Jednostki projektu obsługiwane przez silnik, skróty artefaktów i pseudokod typów/metod | Uruchomiony przez wywołującego klient JEB udostępniający MCP, wybrany przez REA_JEB_MCP_URL; [przewodnik JEB](../providers/jeb-analysis.md) |
@@ -273,6 +279,12 @@ REA eksportuje gotowe do uruchomienia środowisko z podstawowym testem uruchamia
[Dokumentacja środowisk](../agent-environments.md) ·
[Obejrzyj demo w X](https://x.com/reatools/status/2112574822584918075?s=20)
### Środowiska aplikacji desktopowych
REA może też zbudować środowisko aplikacji desktopowej dla Linuksa, z której agent korzysta przez zrzuty ekranu, mysz i klawiaturę. Z jednowierszowej prośby, takiej jak „Zbuduj mi środowisko Gnote, w którym agent dodaje oliwę z oliwek do notatki z listą zakupów”, twój agent instaluje aplikację na lokalnym komputerze budującym, pisze zadanie, eksportuje środowisko i sprawdza zadanie na nowym komputerze. Maszyna, która je buduje, potrzebuje Linuksa na amd64 lub arm64, Dockera i wersji frameworka agentenv wskazanej w przewodniku.
[Konfiguracja środowisk aplikacji desktopowych](../desktop-build-computer.md)
## FAQ
<details>
+13 -1
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · **Português (Brasil)** · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
# REA: Faça engenharia reversa de qualquer coisa
@@ -84,6 +84,10 @@ A configuração oferece suporte ao Claude Code, Codex, Cursor, Gemini CLI, Grok
O MCP usa esquemas de entrada compactos por padrão. Para obter todas as orientações de campos e validação aninhada, defina `REA_MCP_INPUT_SCHEMA_PROFILE=full` no registro MCP. Ambos os perfis mantêm todas as ferramentas e a mesma validação canônica do servidor; veja o guia dos contratos MCP.
A configuração registra diretamente o runtime escolhido e o script de entrada do REA. Ao usar um executor de pacotes, mantenha sua entrada de cache e o runtime; obtenha o pacote em um diretório confiável fora do projeto alvo. Consulte o guia de instalação.
Os esquemas de saída completos são anunciados por padrão. Se o cliente limitar `tools/list`, defina `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` ou `off` no registro MCP. A validação do servidor e os resultados estruturados continuam completos. Consulte “Output schemas” no guia de contratos MCP.
### Peça ao seu agente
```text
@@ -157,6 +161,7 @@ O REA requer Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) ou 26+ (>=26.12.1), alé
| Estrutura ELF sem execução | Seções, segmentos, símbolos/relocações originais e possíveis mecanismos de mitigação identificados por análise estática | pwntools fornecido pelo chamador no Linux x64; [diagnóstico de binários](../guides/native/binary-diagnostics.md) |
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
| Bytecode EVM | Seletores de despacho, offsets de bytes, argumentos inferidos e mutabilidade | Entrada local com bytes brutos ou representação hexadecimal no Linux x64; [guia de EVM sem execução](../guides/evm/evm-bytecode.md) |
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
@@ -172,6 +177,7 @@ O REA requer Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) ou 26+ (>=26.12.1), alé
| Capturas de pacotes | Endpoints, DNS, TLS SNI, distribuição de protocolos e requisições HTTP | tshark e capinfos fornecidos pelo chamador; [guia pcap](../guides/data/pcap-analysis.md) |
| Assemblies .NET | Metadados, instruções CIL, dependências nativas declaradas e comparações de builds | Inspeção estática; [guia de código gerenciado](../guides/managed/managed-code-analysis.md) |
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
| APKs Android | Declarações do manifesto, classes, métodos descompilados e referências | JADX sem interface gráfica e um JDK completo no Linux/macOS/Windows x64; [guia de Android](../guides/android/android-analysis.md) |
| Dispositivos Android | Dispositivos, pacotes, processos, logs, despejos, capturas de tela e transferências de APK/arquivos | adb fornecido pelo chamador (emulador ou aparelho); [guia de ADB](../guides/android/adb-device-analysis.md) |
| Projetos JEB | Unidades de projeto do motor, hashes de artefatos e pseudocódigo de tipos/métodos | Um cliente JEB iniciado pelo chamador servindo MCP, selecionado com REA_JEB_MCP_URL; [guia de JEB](../providers/jeb-analysis.md) |
@@ -273,6 +279,12 @@ O REA exporta um ambiente executável com um teste básico para verificar se ele
[Referência de ambientes](../agent-environments.md) ·
[Veja a demonstração no X](https://x.com/reatools/status/2112574822584918075?s=20)
### Ambientes de aplicativos de desktop
O REA também pode criar um ambiente de um aplicativo de desktop Linux, que um agente usa por capturas de tela, mouse e teclado. A partir de um pedido de uma linha, como "Crie um ambiente do Gnote em que o agente adiciona azeite à nota da lista de compras", seu agente instala o aplicativo em um computador de build local, escreve a tarefa, exporta o ambiente e verifica a tarefa em um computador novo. A máquina que o cria precisa de Linux em amd64 ou arm64, Docker e da versão do framework agentenv fixada pelo guia.
[Configurar ambientes de aplicativos de desktop](../desktop-build-computer.md)
## Perguntas frequentes
<details>
+13 -1
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · **Română**
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · **Română** · [Български](README_bg.md)
# REA: Reverse Engineer Anything
@@ -99,6 +99,10 @@ validării structurilor imbricate. Ambele profiluri păstrează toate uneltele
validarea canonică a serverului. Consultă secțiunea „Compact input schema profile”
din ghidul contractelor MCP.
Configurarea înregistrează direct mediul de execuție ales și scriptul de intrare REA. Dacă folosești un executor de pachete, păstrează intrarea sa din cache și mediul de execuție; obține pachetul dintr-un director de încredere din afara proiectului țintă. Consultă ghidul de instalare.
Schemele complete de ieșire sunt anunțate implicit. Dacă clientul limitează `tools/list`, setează `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` sau `off` în înregistrarea MCP. Validarea serverului și rezultatele structurate rămân complete. Consultă „Output schemas” din ghidul contractelor MCP.
### Cere-i agentului
```text
@@ -199,6 +203,7 @@ Uneltele suplimentare și platformele acceptate depind de ținta analizată:
| Fișiere binare Rust | Nume, versiuni, surse și relații de dependență ale pachetelor crate încorporate prin cargo-auditable | Inspectare statică integrată a fișierelor ELF/PE/Mach-O cu o singură arhitectură; [binare Rust](../rust-binaries.md) |
| Certificate PE | Intrări Authenticode WIN_CERTIFICATE și câmpuri de identitate ale semnatarilor PKCS#7 și certificatelor X.509 | Inspectare statică integrată a fișierelor PE; [certificate PE](../pe-certificates.md) |
| Importuri PE | Numele DLL-urilor importate și încărcate întârziat, ordinale, RVA-uri ale IAT și hash-ul importurilor calculat de pefile | Inspectare statică integrată a fișierelor PE; [importuri PE](../pe-imports.md) |
| Scurtături Windows | Țintă Shell Link, argumente, director de lucru, ExtraData și identificatori Tracker | Inspectare statică integrată a fișierelor LNK; [scurtături Windows](../guides/native/windows-shortcut.md) |
| Note ELF | Proprietari și tipuri PT_NOTE/SHT_NOTE, câmpuri GNU build-id și ABI-tag | Inspectare statică integrată a fișierelor ELF; [note ELF](../elf-notes.md) |
| Întărire binară | PIE, NX, RELRO, CFG și indicatori de antet pentru ELF, PE și Mach-O | Inspecție statică integrată a antetelor; [întărire binară](../binary-hardening.md) |
| Rapoarte Apple IPS de eroare fatală | Metadate .ips, fire de execuție, imagini binare, registre și clase documentate de erori fatale | Inspectare statică integrată a datelor JSON; [Apple IPS](../apple-ips.md) |
@@ -225,6 +230,7 @@ Uneltele suplimentare și platformele acceptate depind de ținta analizată:
| Pachete și resurse | Inventare de fișiere, hash-uri, fișiere plist, structura pachetelor de aplicație Apple și resurse extrase | [Ghidul artefactelor și JavaScript](../guides/javascript/javascript-artifact-reconstruction.md), [aplicații Apple](../guides/apple/apple-application-analysis.md) |
| Comportamentul proceselor | Ieșirea în terminal, interacțiuni, observații despre terminarea proceselor și sistemul de fișiere și comparații între rulări | Linux/macOS cu un PTY nativ; [capturarea proceselor](../guides/runtime/process-capture.md) |
| Executabile PyInstaller | Membri CArchive, versiunea Python, scripturi de intrare și bytecode extras | Fără cerințe suplimentare (doar analiză statică); [aplicații Python împachetate](../python-packaged-applications.md) |
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
Inspectarea statică JavaScript și .NET citește fișierele furnizate fără a rula
aplicația. Capturarea în timpul execuției rulează ținta selectată sau interacționează
@@ -333,6 +339,12 @@ REA exportă un mediu executabil cu un test de bază care verifică pornirea și
[Referință pentru medii](../agent-environments.md) ·
[Vezi demonstrația pe X](https://x.com/reatools/status/2112574822584918075?s=20)
### Medii pentru aplicații desktop
REA poate crea și un mediu pentru o aplicație desktop Linux, pe care un agent o folosește prin capturi de ecran, mouse și tastatură. Dintr-o cerere de un rând, precum „Creează-mi un mediu Gnote în care agentul adaugă ulei de măsline în notița cu lista de cumpărături”, agentul tău instalează aplicația pe un computer de build local, scrie sarcina, exportă mediul și verifică sarcina pe un computer nou. Mașina care îl creează are nevoie de Linux pe amd64 sau arm64, Docker și versiunea frameworkului agentenv fixată de ghid.
[Configurează mediile pentru aplicații desktop](../desktop-build-computer.md)
## Întrebări frecvente
<details>
+13 -1
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · **Русский** · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
# REA: Реверс-инжиниринг чего угодно
@@ -84,6 +84,10 @@ npx rea-agents setup
MCP по умолчанию использует компактные входные схемы. Для полного описания полей и вложенной валидации задайте `REA_MCP_INPUT_SCHEMA_PROFILE=full` в регистрации MCP. Оба профиля сохраняют все инструменты и одинаковую каноническую проверку на сервере; см. руководство по контрактам MCP.
Настройка напрямую регистрирует выбранную среду выполнения и входной скрипт REA. При использовании средства запуска пакетов сохраняйте его запись в кэше и среду выполнения; получайте пакет из доверенного каталога вне целевого проекта. См. руководство по установке.
Полные схемы вывода объявляются по умолчанию. Если клиент ограничивает `tools/list`, задайте `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` или `off` в регистрации MCP. Проверка на сервере и структурированные результаты остаются полными. См. раздел «Output schemas» в руководстве по контрактам MCP.
### Задайте вопрос агенту
```text
@@ -159,6 +163,7 @@ REA требует Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) или 26+ (>=26.1
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
| Binary hardening | PIE, NX, RELRO, CFG and related header flags for ELF, PE and Mach-O | Built-in static header inspection; [binary hardening](../binary-hardening.md) |
| Linux kernel modules | .modinfo keys, __versions CRCs, this_module presence, and signature trailer | Built-in static ELF inspection; [kernel modules](../kernel-modules.md) |
@@ -182,6 +187,7 @@ REA требует Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) или 26+ (>=26.1
| Пакеты и ресурсы | Списки файлов, хеши, plist, структура пакетов Apple и извлечённые ресурсы | [Руководство по артефактам и JavaScript](../guides/javascript/javascript-artifact-reconstruction.md), [приложения Apple](../guides/apple/apple-application-analysis.md) |
| Поведение процессов | Вывод терминала, взаимодействия, наблюдения за завершением и файловой системой, сравнения запусков | Linux/macOS с нативным PTY; [захват процессов](../guides/runtime/process-capture.md) |
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
| Бинарные файлы Go | Встроенная версия компилятора, модули, замены и параметры сборки | Встроенный статический анализ ELF/PE/thin Mach-O; Установка Go не нужна |
| Базы SQLite | Таблицы, столбцы, индексы, представления, триггеры и выбранные строки обычных таблиц | Локальный снимок БД/WAL; Node.js 24.x >=24.15 или 26+ с нативными ограничениями SQLite |
| Объекты кода GPU | Цели CUDA/HIP, параметры и ресурсы выбранных ядер, сохранённый текст PTX | Встроенный статический анализ ELF/PE/fatbin/CUBIN/PTX; [GPU](../gpu-code-objects.md) |
@@ -273,6 +279,12 @@ REA экспортирует готовое к запуску окружение
[Справочник окружений](../agent-environments.md) ·
[Смотреть демо в X](https://x.com/reatools/status/2112574822584918075?s=20)
### Окружения десктопных приложений
REA также может создать окружение десктопного приложения для Linux, которым агент пользуется через снимки экрана, мышь и клавиатуру. По запросу в одну строку, например «Создай окружение Gnote, где агент добавляет оливковое масло в заметку со списком покупок», ваш агент устанавливает приложение на локальный компьютер сборки, пишет задание, экспортирует окружение и проверяет задание на новом компьютере. Машине, которая его собирает, нужны Linux на amd64 или arm64, Docker и версия фреймворка agentenv, указанная в руководстве.
[Настройка окружений десктопных приложений](../desktop-build-computer.md)
## Частые вопросы
<details>
+13 -1
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · **ไทย** · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
# REA: Reverse Engineer Anything
@@ -84,6 +84,10 @@ npx rea-agents setup
MCP ใช้สคีมาอินพุตแบบกระชับโดยปริยาย หากต้องการคำอธิบายฟิลด์และการตรวจสอบแบบซ้อนทั้งหมด ให้ตั้ง `REA_MCP_INPUT_SCHEMA_PROFILE=full` ในการลงทะเบียน MCP ทั้งสองแบบคงเครื่องมือครบและใช้การตรวจสอบมาตรฐานฝั่งเซิร์ฟเวอร์เดียวกัน ดูคู่มือสัญญา MCP
การตั้งค่าจะลงทะเบียนรันไทม์ที่เลือกและสคริปต์เริ่มต้นของ REA โดยตรง หากใช้ตัวรันแพ็กเกจ ให้เก็บรายการแคชและรันไทม์ไว้ และรับแพ็กเกจจากไดเรกทอรีที่เชื่อถือได้นอกโปรเจกต์เป้าหมาย ดูคู่มือการติดตั้ง
ระบบประกาศสคีมาเอาต์พุตฉบับเต็มตามค่าเริ่มต้น หากไคลเอนต์จำกัด `tools/list` ให้ตั้ง `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` หรือ `off` ในการลงทะเบียน MCP การตรวจสอบฝั่งเซิร์ฟเวอร์และผลลัพธ์แบบมีโครงสร้างยังคงครบถ้วน ดูหัวข้อ “Output schemas” ในคู่มือสัญญา MCP
### ถามเอเจนต์
```text
@@ -157,6 +161,7 @@ REA ต้องใช้ Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) หรื
| โครงสร้าง ELF แบบออฟไลน์ | เซกชัน เซกเมนต์ สัญลักษณ์/รีโลเคชันต้นฉบับ และตัวเลือกกลไกป้องกันที่พบจากการวิเคราะห์แบบสถิต | pwntools ที่ผู้ใช้จัดเตรียมบน Linux x64; [การวินิจฉัยไบนารี](../guides/native/binary-diagnostics.md) |
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
| ไบต์โค้ด EVM | ตัวเลือกฟังก์ชันสำหรับการเรียก ออฟเซ็ตไบต์ อาร์กิวเมนต์และความสามารถในการเปลี่ยนสถานะที่อนุมานได้ | ไฟล์บนเครื่องที่มีไบต์ดิบหรือข้อมูลเลขฐานสิบหกบน Linux x64; [คู่มือ EVM แบบออฟไลน์](../guides/evm/evm-bytecode.md) |
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
@@ -172,6 +177,7 @@ REA ต้องใช้ Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) หรื
| การจับแพ็กเก็ต | จุดเชื่อมต่อ, DNS, TLS SNI, การกระจายโปรโตคอล และคำขอ HTTP | tshark และ capinfos ที่ผู้เรียกจัดเตรียม; [คู่มือ pcap](../guides/data/pcap-analysis.md) |
| แอสเซมบลี .NET | เมทาดาทา คำสั่ง CIL การพึ่งพาเนทีฟที่ประกาศไว้ และการเปรียบเทียบผลการบิลด์ | การตรวจสอบแบบสถิต; [คู่มือโค้ดแบบจัดการ](../guides/managed/managed-code-analysis.md) |
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
| APK ของ Android | การประกาศใน manifest คลาส เมธอดที่ดีคอมไพล์ และการอ้างอิง | JADX แบบไม่มี GUI และ JDK แบบเต็มบน Linux/macOS/Windows x64; [คู่มือ Android](../guides/android/android-analysis.md) |
| อุปกรณ์ Android | อุปกรณ์ แพ็กเกจ โพรเซส บันทึก ดัมพ์ ภาพหน้าจอ และการถ่ายโอน APK/ไฟล์ | adb ที่ผู้เรียกจัดเตรียม (โปรแกรมจำลองหรืออุปกรณ์จริง); [คู่มือ ADB](../guides/android/adb-device-analysis.md) |
| โปรเจกต์ JEB | หน่วยโปรเจกต์จากเอนจิน, แฮชของอาร์ติแฟกต์ และซูโดโค้ดของไทป์/เมท็อด | ไคลเอนต์ JEB ที่ผู้เรียกเริ่มและให้บริการ MCP เลือกด้วย REA_JEB_MCP_URL; [คู่มือ JEB](../providers/jeb-analysis.md) |
@@ -273,6 +279,12 @@ REA ส่งออกสภาพแวดล้อมที่รันได
[เอกสารอ้างอิงสภาพแวดล้อม](../agent-environments.md) ·
[ชมเดโมบน X](https://x.com/reatools/status/2112574822584918075?s=20)
### สภาพแวดล้อมของแอปเดสก์ท็อป
REA ยังสร้างสภาพแวดล้อมของแอปเดสก์ท็อปบน Linux ที่เอเจนต์ใช้งานผ่านภาพหน้าจอ เมาส์ และคีย์บอร์ดได้ด้วย จากคำขอเพียงบรรทัดเดียว เช่น "สร้างสภาพแวดล้อม Gnote ที่เอเจนต์เพิ่มน้ำมันมะกอกลงในโน้ตรายการซื้อของ" เอเจนต์ของคุณจะติดตั้งแอปบนคอมพิวเตอร์สำหรับบิลด์ในเครื่อง เขียนงาน ส่งออกสภาพแวดล้อม และตรวจสอบงานบนคอมพิวเตอร์เครื่องใหม่ เครื่องที่ใช้สร้างต้องมี Linux บน amd64 หรือ arm64, Docker และ agentenv framework เวอร์ชันที่คู่มือกำหนด
[ตั้งค่าสภาพแวดล้อมของแอปเดสก์ท็อป](../desktop-build-computer.md)
## คำถามที่พบบ่อย
<details>
+13 -1
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · **Türkçe** · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
# REA: Her şeyi tersine mühendislikle inceleyin
@@ -84,6 +84,10 @@ Kurulum Claude Code, Codex, Cursor, Gemini CLI, Grok Build ve [diğer ajanları]
MCP varsayılan olarak kompakt girdi şemaları kullanır. Tam alan açıklamaları ve iç içe doğrulama ayrıntıları için MCP kaydında `REA_MCP_INPUT_SCHEMA_PROFILE=full` ayarlayın. Her iki profil tüm araçları ve aynı kanonik sunucu doğrulamasını korur; MCP sözleşme rehberine bakın.
Kurulum, seçilen çalışma zamanını ve REA giriş betiğini doğrudan kaydeder. Paket çalıştırıcısı kullanıyorsanız önbellek girdisini ve çalışma zamanını koruyun; paketi hedef projenin dışında güvenilir bir dizinden edinin. Kurulum rehberine bakın.
Tam çıktı şemaları varsayılan olarak duyurulur. İstemciniz `tools/list` boyutunu sınırlıyorsa MCP kaydında `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` veya `off` ayarlayın. Sunucu doğrulaması ve yapılandırılmış sonuçlar tam kalır. MCP sözleşmeleri rehberindeki “Output schemas” bölümüne bakın.
### Ajanınıza sorun
```text
@@ -157,6 +161,7 @@ REA; Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) veya 26+ (>=26.12.1) ve npm gere
| Rust ikili dosyaları | Gömülü cargo-auditable crate adları, sürümleri, kaynakları ve bağımlılık ilişkileri | Yerleşik statik ELF/PE/thin Mach-O incelemesi; [Rust ikili dosyaları](../rust-binaries.md) |
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
| Binary hardening | PIE, NX, RELRO, CFG and related header flags for ELF, PE and Mach-O | Built-in static header inspection; [binary hardening](../binary-hardening.md) |
| Apple IPS crashes | .ips metadata, threads, images, registers and crash classes | Built-in static JSON inspection; [Apple IPS](../apple-ips.md) |
@@ -172,6 +177,7 @@ REA; Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) veya 26+ (>=26.12.1) ve npm gere
| Kaydedilmiş ağ yakalamaları | İstekler, yanıtlar, erişilebilir yük içerikleri ve kaynak konumları | HAR veya Fiddler Everywhere SAZ; Linux'ta native mitmproxy için mitmdump; [ağ yakalama rehberi](../guides/web/web-network-captures.md) |
| .NET derlemeleri | Meta veriler, CIL talimatları, bildirilmiş yerel bağımlılıklar ve derleme karşılaştırmaları | Statik inceleme; [yönetilen kod rehberi](../guides/managed/managed-code-analysis.md) |
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
| Android APK'leri | Manifest bildirimleri, sınıflar, tersine derlenmiş metotlar ve referanslar | Linux/macOS/Windows x64 üzerinde arayüzsüz JADX ve tam bir JDK; [Android rehberi](../guides/android/android-analysis.md) |
| Android cihazları | Cihazlar, paketler, süreçler, günlükler, dökümler, ekran görüntüleri ve APK/dosya aktarımları | Çağıranın sağladığı adb (emülatör veya cihaz); [ADB rehberi](../guides/android/adb-device-analysis.md) |
| JEB projeleri | Motor destekli proje birimleri, artefakt özetleri ve tür/metot sözdekodu | Çağıranın başlattığı, MCP sunan bir JEB istemcisi, REA_JEB_MCP_URL ile seçilir; [JEB rehberi](../providers/jeb-analysis.md) |
@@ -267,6 +273,12 @@ REA, çalıştırılabilir bir ortamı ve başlayıp yanıt verdiğini kontrol e
[Ortam referansı](../agent-environments.md) ·
[Demoyu X’te izleyin](https://x.com/reatools/status/2112574822584918075?s=20)
### Masaüstü uygulama ortamları
REA, bir ajanın ekran görüntüleri, fare ve klavye ile kullandığı bir Linux masaüstü uygulamasının ortamını da oluşturabilir. “Ajanın alışveriş listesi notuna zeytinyağı eklediği bir Gnote ortamı oluştur” gibi tek satırlık bir istekten ajanınız uygulamayı yerel bir derleme bilgisayarına kurar, görevi yazar, ortamı dışa aktarır ve görevi yeni bir bilgisayarda kontrol eder. Ortamı oluşturan makinede amd64 veya arm64 üzerinde Linux, Docker ve kılavuzun sabitlediği agentenv framework sürümü gerekir.
[Masaüstü uygulama ortamlarını kurun](../desktop-build-computer.md)
## Sık sorulan sorular
<details>
+13 -1
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · **Українська** · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
# REA: Реверс-інжиніринг будь-чого
@@ -84,6 +84,10 @@ npx rea-agents setup
MCP типово використовує компактні вхідні схеми. Для повного опису полів і вкладеної перевірки задайте `REA_MCP_INPUT_SCHEMA_PROFILE=full` у реєстрації MCP. Обидва профілі зберігають усі інструменти й однакову канонічну перевірку сервера; див. посібник контрактів MCP.
Налаштування безпосередньо реєструє вибране середовище виконання та стартовий скрипт REA. Якщо ви використовуєте засіб запуску пакетів, збережіть його запис у кеші та середовище виконання; отримуйте пакет із довіреного каталогу поза цільовим проєктом. Див. посібник зі встановлення.
Повні схеми виводу оголошуються за замовчуванням. Якщо клієнт обмежує `tools/list`, задайте `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` або `off` у реєстрації MCP. Перевірка сервера та структуровані результати залишаються повними. Див. розділ «Output schemas» у посібнику з контрактів MCP.
### Запитайте агента
```text
@@ -157,6 +161,7 @@ REA потребує Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) або 26+ (>=26
| Структура ELF без запуску | Секції, сегменти, початкові символи/релокації та можливі захисні механізми за даними статичного аналізу | pwntools, наданий стороною, що викликає інструмент, у Linux x64; [діагностика бінарних файлів](../guides/native/binary-diagnostics.md) |
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
| Байт-код EVM | Селектори диспетчеризації, зміщення байтів, виведені припущення про аргументи та змінюваність стану | Локальні необроблені байти або шістнадцяткове представлення у Linux x64; [посібник EVM без запуску](../guides/evm/evm-bytecode.md) |
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
@@ -172,6 +177,7 @@ REA потребує Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) або 26+ (>=26
| Захоплення пакетів | Кінцеві точки, DNS, TLS SNI, розподіл протоколів та HTTP-запити | Надані викликаючою стороною tshark та capinfos; [підручник pcap](../guides/data/pcap-analysis.md) |
| Збірки .NET | Метадані, інструкції CIL, оголошені нативні залежності й порівняння збірок | Статична перевірка; [посібник керованого коду](../guides/managed/managed-code-analysis.md) |
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
| Android APK | Оголошення маніфесту, класи, декомпільовані методи й посилання | JADX без графічного інтерфейсу й повний JDK у Linux/macOS/Windows x64; [посібник Android](../guides/android/android-analysis.md) |
| Пристрої Android | Пристрої, пакети, процеси, журнали, дампи, знімки екрана та передавання APK/файлів | adb, наданий викликаючою стороною (емулятор або пристрій); [підручник ADB](../guides/android/adb-device-analysis.md) |
| Проєкти JEB | Єдиниці проєкту від рушія, дайджести артефактів і псевдокод типів/методів | Запущений викликаною стороною клієнт JEB з MCP, обирається через REA_JEB_MCP_URL; [посібник JEB](../providers/jeb-analysis.md) |
@@ -273,6 +279,12 @@ REA експортує готове до запуску середовище з
[Довідник середовищ](../agent-environments.md) ·
[Дивитися демо в X](https://x.com/reatools/status/2112574822584918075?s=20)
### Середовища настільних застосунків
REA також може створити середовище настільного застосунку для Linux, яким агент користується через знімки екрана, мишу й клавіатуру. За запитом в один рядок, як-от «Створи середовище Gnote, де агент додає оливкову олію до нотатки зі списком покупок», ваш агент встановлює застосунок на локальний комп’ютер збирання, пише завдання, експортує середовище й перевіряє завдання на новому комп’ютері. Машині, яка його збирає, потрібні Linux на amd64 або arm64, Docker і версія фреймворку agentenv, зазначена в посібнику.
[Налаштування середовищ настільних застосунків](../desktop-build-computer.md)
## Поширені запитання
<details>
+13 -1
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · **Roman Urdu** · [Română](README_ro.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · **Roman Urdu** · [Română](README_ro.md) · [Български](README_bg.md)
# REA: Reverse Engineer Anything
@@ -99,6 +99,10 @@ set karein. Dono profiles mein tamam tools aur canonical server validation
maujood rehte hain. MCP contracts guide ka "Compact input schema profile"
section dekhein.
Setup chuna hua runtime aur REA entry script seedha register karta hai. Package runner use karne par uski cache entry aur runtime barqarar rakhein; package target project se bahar kisi bharosemand directory se hasil karein. Installation guide dekhein.
Mukammal output schemas default mein advertise hote hain. Agar client `tools/list` ko limit karta hai to MCP registration mein `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` ya `off` set karein. Server validation aur structured results mukammal rehte hain. MCP contracts guide ka “Output schemas” section dekhein.
### Apne agent se kahein
```text
@@ -199,6 +203,7 @@ Mazeed tools aur host support target par depend karte hain:
| Rust binaries | Embedded cargo-auditable crate names, versions, sources aur dependency edges | Built-in static ELF/PE/thin Mach-O inspection; [Rust binaries](../rust-binaries.md) |
| PE certificates | Authenticode WIN_CERTIFICATE entries aur PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
| PE imports | Import aur delay-load DLL names, ordinals, IAT RVAs aur pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id aur ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
| Binary hardening | PIE, NX, RELRO, CFG and related header flags for ELF, PE and Mach-O | Built-in static header inspection; [binary hardening](../binary-hardening.md) |
| Linux kernel modules | .modinfo keys, __versions CRCs, this_module presence, and signature trailer | Built-in static ELF inspection; [kernel modules](../kernel-modules.md) |
@@ -225,6 +230,7 @@ Mazeed tools aur host support target par depend karte hain:
| Packages aur resources | File inventories, digests, plists, Apple bundle structure aur extracted resources | [Artifact aur JavaScript guide](../guides/javascript/javascript-artifact-reconstruction.md), [Apple applications](../guides/apple/apple-application-analysis.md) |
| Process behavior | Terminal output, interactions, exit aur filesystem observations aur runs ka comparison | Native PTY ke saath Linux/macOS; [process capture](../guides/runtime/process-capture.md) |
| PyInstaller executables | CArchive members, Python version, entry scripts aur extracted bytecode | Koi additional tool nahi (sirf static analysis); [Python packaged applications](../python-packaged-applications.md) |
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
Static JavaScript aur .NET inspection di hui files ko application chalaye baghair
parhti hai. Runtime capture aapki user permissions se selected target ko chalata
@@ -332,6 +338,12 @@ REA chalne ke liye tayyar environment aur aik bunyadi test export karta hai jo u
[Environment reference](../agent-environments.md) ·
[X par demo dekhein](https://x.com/reatools/status/2112574822584918075?s=20)
### Desktop app environments
REA Linux desktop app ka environment bhi bana sakta hai, jise agent screenshots, mouse aur keyboard se istemal karta hai. Aik line ki request se, jaise "Mere liye Gnote environment banao jis mein agent shopping list note mein olive oil shamil kare", aap ka agent app ko local build computer par install karta hai, task likhta hai, environment export karta hai aur naye computer par task check karta hai. Ise banane wali machine ko amd64 ya arm64 par Linux, Docker aur guide mein muqarrar agentenv framework version chahiye.
[Desktop app environments setup karein](../desktop-build-computer.md)
## FAQ
<details>
+13 -1
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · **Tiếng Việt** · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
# REA: Kỹ thuật dịch ngược cho mọi thứ
@@ -84,6 +84,10 @@ Quá trình thiết lập hỗ trợ Claude Code, Codex, Cursor, Gemini CLI, Gro
MCP mặc định dùng schema đầu vào gọn. Để có hướng dẫn đầy đủ về trường và xác thực lồng nhau, đặt `REA_MCP_INPUT_SCHEMA_PROFILE=full` trong đăng ký MCP. Cả hai cấu hình giữ toàn bộ công cụ và cùng xác thực chuẩn ở máy chủ; xem hướng dẫn hợp đồng MCP.
Thiết lập đăng ký trực tiếp runtime đã chọn và script khởi chạy REA. Khi dùng trình chạy gói, hãy giữ mục cache và runtime đó; tải gói từ một thư mục đáng tin cậy bên ngoài dự án đích. Xem hướng dẫn cài đặt.
Schema đầu ra đầy đủ được công bố theo mặc định. Nếu client giới hạn `tools/list`, hãy đặt `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` hoặc `off` trong cấu hình MCP. Xác thực phía server và kết quả có cấu trúc vẫn đầy đủ. Xem mục “Output schemas” trong hướng dẫn hợp đồng MCP.
### Hỏi tác nhân
```text
@@ -159,6 +163,7 @@ REA yêu cầu Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) hoặc 26+ (>=26.12.1)
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
| Binary hardening | PIE, NX, RELRO, CFG and related header flags for ELF, PE and Mach-O | Built-in static header inspection; [binary hardening](../binary-hardening.md) |
| Linux kernel modules | .modinfo keys, __versions CRCs, this_module presence, and signature trailer | Built-in static ELF inspection; [kernel modules](../kernel-modules.md) |
@@ -182,6 +187,7 @@ REA yêu cầu Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) hoặc 26+ (>=26.12.1)
| Gói và tài nguyên | Danh sách tệp, giá trị băm, plist, cấu trúc bundle Apple và tài nguyên được trích xuất | [Hướng dẫn hiện vật phần mềm và JavaScript](../guides/javascript/javascript-artifact-reconstruction.md), [ứng dụng Apple](../guides/apple/apple-application-analysis.md) |
| Hành vi tiến trình | Đầu ra terminal, tương tác, quan sát khi thoát và hệ thống tệp, cùng so sánh các lần chạy | Linux/macOS có PTY gốc; [ghi lại tiến trình](../guides/runtime/process-capture.md) |
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
| Tệp nhị phân Go | Phiên bản trình biên dịch nhúng, mô-đun, thay thế và thiết lập build | Kiểm tra tĩnh tích hợp ELF/PE/thin Mach-O; Không cần cài Go |
| Cơ sở dữ liệu SQLite | Bảng, cột, chỉ mục, view, trigger và hàng được chọn từ bảng thông thường | Ảnh chụp cơ sở dữ liệu/WAL cục bộ; Node.js 24.x >=24.15 hoặc 26+ có giới hạn SQLite native |
| Đối tượng mã GPU | Đích CUDA/HIP, tham số và tài nguyên kernel được chọn, văn bản PTX được giữ lại | Kiểm tra tĩnh tích hợp ELF/PE/fatbin/CUBIN/PTX; [GPU](../gpu-code-objects.md) |
@@ -273,6 +279,12 @@ REA xuất môi trường chạy được cùng bài kiểm tra cơ bản để
[Tài liệu tham chiếu môi trường](../agent-environments.md) ·
[Xem bản demo trên X](https://x.com/reatools/status/2112574822584918075?s=20)
### Môi trường ứng dụng desktop
REA cũng có thể xây dựng môi trường cho một ứng dụng desktop Linux mà tác tử dùng qua ảnh chụp màn hình, chuột và bàn phím. Từ một yêu cầu một dòng, chẳng hạn "Tạo cho tôi một môi trường Gnote trong đó tác tử thêm dầu ô liu vào ghi chú danh sách mua sắm", tác tử của bạn cài ứng dụng trên một máy tính dựng cục bộ, viết tác vụ, xuất môi trường và kiểm tra tác vụ trên một máy tính mới. Máy dựng môi trường cần Linux trên amd64 hoặc arm64, Docker và phiên bản framework agentenv mà hướng dẫn chỉ định.
[Thiết lập môi trường ứng dụng desktop](../desktop-build-computer.md)
## Câu hỏi thường gặp
<details>
+13 -1
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · **繁體中文** · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
# REA:逆向一切
@@ -84,6 +84,10 @@ npx rea-agents setup
MCP 預設使用精簡輸入 Schema,以減少上下文開銷。需要完整欄位說明和巢狀驗證細節時,請在 MCP 註冊中設定 `REA_MCP_INPUT_SCHEMA_PROFILE=full`。兩種設定都保留完整工具集和標準的伺服器驗證;見 MCP 合約指南。
設定會直接登記所選執行環境和 REA 入口指令碼。使用套件執行器時,請保留其快取項目及執行環境,並從目標專案以外的可信任目錄取得套件。 請參閱安裝指南。
預設會公布完整輸出 Schema。若用戶端限制 `tools/list` 的大小,請在 MCP 登記中設定 `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` 或 `off`。伺服器驗證和結構化結果仍保持完整。 請參閱 MCP 合約指南中的「Output schemas」。
### 詢問 AI 代理
```text
@@ -160,6 +164,7 @@ REA 需要 Node.js 22.x(>=22.23.4)、24.x(>=24.22.1)或 26+ (>=26.12.1)
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
| Binary hardening | PIE, NX, RELRO, CFG and related header flags for ELF, PE and Mach-O | Built-in static header inspection; [binary hardening](../binary-hardening.md) |
| Apple IPS crashes | .ips metadata, threads, images, registers and crash classes | Built-in static JSON inspection; [Apple IPS](../apple-ips.md) |
@@ -172,6 +177,7 @@ REA 需要 Node.js 22.x(>=22.23.4)、24.x(>=24.22.1)或 26+ (>=26.12.1)
| 封包擷取 | 端點、DNS、TLS SNI、通訊協定分佈和 HTTP 請求 | 呼叫端提供的 tshark 和 capinfos;[pcap 指南](../guides/data/pcap-analysis.md) |
| .NET 程式集 | 中繼資料、CIL 指令、聲明的原生依賴和建置對比 | 靜態檢查;[托管程式碼指南](../guides/managed/managed-code-analysis.md) |
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
| Android APK | 清單聲明、類別、反編譯的方法和引用 | Linux/macOS/Windows x64 上的無界面 JADX 和完整 JDK;[Android 指南](../guides/android/android-analysis.md) |
| Android 裝置 | 裝置、套件、程序、日誌、傾印、螢幕擷取以及 APK/檔案傳輸 | 呼叫端提供的 adb(模擬器或實體裝置);[ADB 指南](../guides/android/adb-device-analysis.md) |
| JEB 專案 | 引擎支援的專案單元、成品摘要和型別/方法的虛擬碼 | 由呼叫端啟動、提供 MCP 的 JEB 用戶端,透過 REA_JEB_MCP_URL 選擇;[JEB 指南](../providers/jeb-analysis.md) |
@@ -273,6 +279,12 @@ REA 匯出可直接執行的環境,並附帶基本測試,檢查環境能否
[環境參考文件](../agent-environments.md) ·
[在 X 上觀看示範](https://x.com/reatools/status/2112574822584918075?s=20)
### 桌面應用程式環境
REA 也能為 Linux 桌面應用程式建立環境,代理透過螢幕截圖、滑鼠和鍵盤使用它。只要一行請求,例如「幫我建立一個 Gnote 環境,讓代理在購物清單筆記中加入橄欖油」,你的代理就會在本機建置電腦上安裝應用程式、撰寫任務、匯出環境,並在全新的電腦上檢查任務。建立環境的機器需要 amd64 或 arm64 上的 Linux、Docker,以及指南固定的 agentenv 框架版本。
[設定桌面應用程式環境](../desktop-build-computer.md)
## 常見問題
<details>
+13 -1
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · **简体中文** · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
# REA:逆向一切
@@ -84,6 +84,10 @@ npx rea-agents setup
MCP 默认使用紧凑输入 Schema 来减少上下文开销。需要完整字段说明和嵌套验证细节时,在 MCP 注册中设置 `REA_MCP_INPUT_SCHEMA_PROFILE=full`。两种配置都保留完整工具集和规范的服务端验证;见 MCP 合约指南。
设置会直接注册所选运行时和 REA 入口脚本。使用包运行器时,请保留其缓存条目和运行时,并从目标项目以外的可信目录获取包。 请参阅安装指南。
默认公布完整输出 Schema。如果客户端限制 `tools/list` 的大小,请在 MCP 注册中设置 `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` 或 `off`。服务端验证和结构化结果仍保持完整。 请参阅 MCP 合约指南中的“Output schemas”。
### 询问智能体
```text
@@ -160,6 +164,7 @@ REA 需要 Node.js 22.x(>=22.23.4)、24.x(>=24.22.1)或 26+ (>=26.12.1)
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
| Binary hardening | PIE, NX, RELRO, CFG and related header flags for ELF, PE and Mach-O | Built-in static header inspection; [binary hardening](../binary-hardening.md) |
| Apple IPS crashes | .ips metadata, threads, images, registers and crash classes | Built-in static JSON inspection; [Apple IPS](../apple-ips.md) |
@@ -172,6 +177,7 @@ REA 需要 Node.js 22.x(>=22.23.4)、24.x(>=24.22.1)或 26+ (>=26.12.1)
| 数据包捕获 | 端点、DNS、TLS SNI、协议分布和 HTTP 请求 | 调用方提供的 tshark 和 capinfos;[pcap 指南](../guides/data/pcap-analysis.md) |
| .NET 程序集 | 元数据、CIL 指令、声明的原生依赖和构建对比 | 静态检查;[托管代码指南](../guides/managed/managed-code-analysis.md) |
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
| Android APK | 清单声明、类、反编译的方法和引用 | Linux/macOS/Windows x64 上的无界面 JADX 和完整 JDK;[Android 指南](../guides/android/android-analysis.md) |
| Android 设备 | 设备、软件包、进程、日志、转储、屏幕截图以及 APK/文件传输 | 调用方提供的 adb(模拟器或实体设备);[ADB 指南](../guides/android/adb-device-analysis.md) |
| JEB 项目 | 引擎支持的项目单元、工件摘要和类型/方法的伪代码 | 由调用方启动、提供 MCP 的 JEB 客户端,通过 REA_JEB_MCP_URL 选择;[JEB 指南](../providers/jeb-analysis.md) |
@@ -271,6 +277,12 @@ REA 导出可直接运行的环境,并附带基本测试,检查环境能否
[环境参考文档](../agent-environments.md) ·
[在 X 上观看演示](https://x.com/reatools/status/2112574822584918075?s=20)
### 桌面应用环境
REA 也能为 Linux 桌面应用构建环境,智能体通过截图、鼠标和键盘使用它。只需一行请求,例如“帮我构建一个 Gnote 环境,让智能体在购物清单笔记中加入橄榄油”,你的智能体就会在本地构建计算机上安装应用、编写任务、导出环境,并在全新的计算机上检查任务。构建环境的机器需要 amd64 或 arm64 上的 Linux、Docker,以及指南固定的 agentenv 框架版本。
[设置桌面应用环境](../desktop-build-computer.md)
## 常见问题
<details>
+5
View File
@@ -28,6 +28,11 @@ this effective scope. A claim verifier must commit to its own surfaces and
their reachable dependencies, including their artifact and implemented-owner
digests. Callers do not need to duplicate the transitive closure in the request.
Listed `residual_unknown_ids` select unknown identities from the Evidence bundle.
The evaluator uses each identity's latest revision: resolved questions do not
block the boundary, while reopened questions do. An active, unallowed question
retains its cited supporting, contradicting and mutation Evidence in the result.
## Comparable verifier Evidence
At least one record explicitly cited by the latest verifier observation must
+64 -6
View File
@@ -10,6 +10,9 @@ and [session discovery](#identity-and-discovery). See [transports](#transports)
for the opt-in HTTP listener, [cancellation](#progress-and-cancellation)
for partial-result recovery and [first-query deadlines](#ghidra-first-query-deadlines-and-recovery)
when a cold provider exceeds the client's wait.
The shared [caller-path](#caller-selected-paths) and
[publication](#evidence-publication-and-source-recovery) fields also apply to CLI
Evidence.
## Tool results
@@ -221,7 +224,7 @@ graph, while `search_scope.discovery` describes whether discovery of applicable
direct relationships is established. A missing goal is `unknown` when either
discovery or a relationship read is unestablished. A found path is shortest
within the observed graph; undiscovered calls may produce a shorter path.
`truncated` describes relationship reads, not unestablished discovery.
`truncated` describes relationship reads, not unestablished discovery. Ghidra's recorded incoming references do not establish every computed caller; computed outgoing candidates likewise retain unknown callee discovery. IDA function-edge replies retain their observed truncation status while unclassified call targets remain unknown in discovery.
`build_call_path` applies the same distinction to supplied function Evidence:
its `search_scope.exhaustive` describes the supplied graph and
`search_scope.observed_status` preserves that graph's result. Evidence without
@@ -519,6 +522,23 @@ that buffer. It does not raise REA's reserved single-string limit, which is
raise that Node ceiling. It does not change analysis coverage or retained
content. Ordinary responses keep their existing complete result contract.
### Caller-selected paths
Evidence can include `caller_input_path` for the verbatim primary selection and
`caller_input_paths` for named auxiliary selections. Each auxiliary value is a
string or an ordered array of strings; repeated selections preserve order and
duplicates. Consumers must accept both forms.
These fields record request provenance outside semantic Evidence identity.
They do not replace the inspected identity in `subject` or prove format validity.
One-shot binary CLI requests retain relative spelling and symlink aliases;
provider inspections also keep the established `parameters.input_path` field.
Older records and workflows without a caller-path binding omit these fields.
A workflow's explicit sensitive-value policy can exclude primary and auxiliary
spellings independently; do not infer a missing primary from an auxiliary value.
See [capture redaction](../guides/web/web-network-captures.md) for its policy.
### Input validation resource allowance
Both HTTP and stdio admit at most 1,024 combined array elements and object
@@ -1356,11 +1376,9 @@ uses `cleanup_incomplete` and lists only the owned resource kinds that remain.
Once those owners confirm cleanup, composed failures recover their original
typed primary outcome and recovery guidance. Historical composition diagnostics
remain in `details.cleanup_history`, separate from the primary diagnostics.
An atomic Evidence bundle or snapshot write can publish its complete output
before staging cleanup fails. In that case, `details.published: true`,
`details.published_path`, and `details.bytes` retain the publication receipt.
Use that receipt to distinguish completed publication from a write that never
committed. Staging resources remain owned until cleanup is verified.
For written Evidence and snapshot outcomes, use the
[publication receipt](#evidence-publication-and-source-recovery) separately from
cleanup status.
Native call tracing and process capture retain available observations in
`details.partial_observation` on failure, including when cleanup succeeds.
The observation reports its partial coverage; cleanup details describe host
@@ -1432,6 +1450,46 @@ through provider cleanup, including repeated delivery by package runners.
Existing controlled-process cleanup and provider shutdown rules still apply;
REA never kills a process it cannot prove it owns.
### Evidence publication and source recovery
An atomic Evidence bundle or snapshot write can commit before later cancellation
or staging cleanup failure. Cancellation observed before publication leaves the
destination unchanged; once publication has started, the owning operation can
complete it.
Inspect the returned receipt before retrying or replacing output:
| Outcome | Receipt |
| ----------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| Evidence or snapshot publication committed, then staging cleanup failed | `details.published: true`, `details.published_path`, and `details.bytes` |
| CLI Evidence delivery cancelled after its bundle committed | `details.diagnostics.evidence_bundle` with the written path and byte count |
Receipt paths can be omitted when unavailable or explicitly excluded. A missing
path alone does not establish that publication failed.
A publication failure can retain completed Evidence in
`details.partial_observation`. The receipt confirms written output, not that
cleanup succeeded or every analysis stage completed. Staging resources remain
owned until cleanup is verified. Other output kinds use their own contracts,
such as [environment directory publication](../getting-started/cli.md#export-an-environment-bundle)
and [decompile output receipts](../guides/native/native-investigation.md).
For a requested one-shot Evidence bundle that did not commit, the error can
include `details.source_closure` when completed Evidence has source records or
links, or source collection failed. `publication` is `not_published`.
When collection yields source facts, `records` contains captured Evidence within
64 KiB; explicit sensitivity exclusions can withhold all inline records.
`omitted` lists up to 64 other identities, and `omitted_count` gives the total:
- `not_captured`: this invocation has no record to return; its ancestry remains unknown.
- `not_inlined`: the record was captured but is outside this bounded response.
`complete` is true only when source inspection succeeded and every cited record
is included or embedded in the observation. On inspection failure,
`collection_failure` names the error type and closure stays unknown. Captured
records can still be returned, but record and omission fields can be absent if
collection itself failed. The original operation failure remains primary.
The one-shot process retains nothing after exit; rerunning is a new observation.
## Request scope and local effects
Each tool request names the target and lifecycle it will use. Browser calls
+3 -1
View File
@@ -129,7 +129,9 @@ separately from its type and flags, and
REA preserves known empty names separately from unavailable names; an unavailable
name table still leaves `.dep-v0` presence unknown.
The hash is not a claim that that compiler produced the binary. Several
distinct hashes leave a single commit unknown.
distinct hashes leave a single commit unknown. Windows builds join the rest of
the path with a backslash, as in `/rustc/<40-hex>\library\core`, and that form
counts too.
## Limits and failures
+26 -9
View File
@@ -1,17 +1,34 @@
# Feature specifications
Feature specifications are grouped by domain and meaningful feature slug. Each
directory owns one `spec.md`, one `plan.md` and one `tasks.md`.
This directory indexes proposals and implementation records. It is not a catalog
of current capabilities; use the [documentation directory](../README.md) for
current guides. Preserve original requirements and dated verification evidence
when later increments change behavior.
New feature directories use one `spec.md`, one `plan.md` and one `tasks.md`.
Some historical records have fewer artifacts; their presence or absence does not
establish completion. Do not invent past plans or completed tasks to fill gaps.
Follow [documentation ownership and authoring](../development/documentation.md#feature-lifecycle)
for the specification lifecycle, roadmap granularity and producer-owned contracts.
for new work, roadmap granularity and producer-owned contracts.
## Documentation
## Environment roadmaps
- [Organization](documentation/organization/spec.md)
([plan](documentation/organization/plan.md), [tasks](documentation/organization/tasks.md))
- [Agent environments](agent-environments/README.md)
- [Desktop application environments](desktop-app-environments/README.md)
## Native
## Other feature records
- [Go static string-header literal recovery](native/go-string-literals/spec.md)
([plan](native/go-string-literals/plan.md), [tasks](native/go-string-literals/tasks.md))
- [Core WebAssembly interface comparison (#2356)](2356-wasm-interface-comparison/spec.md) ([plan](2356-wasm-interface-comparison/plan.md), [tasks](2356-wasm-interface-comparison/tasks.md), [verification](2356-wasm-interface-comparison/verification.md))
- [Inspect APK signature schemes (v1–v3.1)](apk-signature/spec.md)
- [Documentation organization](documentation/organization/spec.md) ([plan](documentation/organization/plan.md), [tasks](documentation/organization/tasks.md), [verification](documentation/organization/verification.md))
- [V8 cached-data compilation boundaries](javascript/v8-cached-data/spec.md) ([plan](javascript/v8-cached-data/plan.md), [tasks](javascript/v8-cached-data/tasks.md))
- [Android `.note.android.ident` ELF note decoding](native/android-elf-ident-note/spec.md) ([plan](native/android-elf-ident-note/plan.md), [tasks](native/android-elf-ident-note/tasks.md))
- [Native call source coordinates](native/call-source-locations/spec.md) ([plan](native/call-source-locations/plan.md), [tasks](native/call-source-locations/tasks.md), [verification](native/call-source-locations/verification.md))
- [Go static string-header literal recovery](native/go-string-literals/spec.md) ([plan](native/go-string-literals/plan.md), [tasks](native/go-string-literals/tasks.md))
- [Windows Shell Link shortcut inspection](native/windows-shortcut/spec.md) ([plan](native/windows-shortcut/plan.md), [tasks](native/windows-shortcut/tasks.md))
- [Solidity terminal metadata inspection](solidity/cbor-metadata/spec.md) ([plan](solidity/cbor-metadata/plan.md), [tasks](solidity/cbor-metadata/tasks.md), [verification](solidity/cbor-metadata/verification.md))
- [Inspect a V8 code cache container](v8/code-cache-inspection/spec.md) ([plan](v8/code-cache-inspection/plan.md), [tasks](v8/code-cache-inspection/tasks.md))
- [Deno compile executable inventory and extraction](artifacts/deno-standalone/spec.md) ([plan](artifacts/deno-standalone/plan.md), [tasks](artifacts/deno-standalone/tasks.md))
- [ELF unwind function ranges](native/elf-unwind-ranges/spec.md) ([plan](native/elf-unwind-ranges/plan.md), [tasks](native/elf-unwind-ranges/tasks.md))
- [Linux kernel build config](native/kernel-build-config/spec.md) ([plan](native/kernel-build-config/plan.md), [tasks](native/kernel-build-config/tasks.md))
- [Native initializers](native/native-initializers/spec.md) ([plan](native/native-initializers/plan.md), [tasks](native/native-initializers/tasks.md))
+12
View File
@@ -81,3 +81,15 @@ configuration. Retrieval rewards demonstrate particular task outcomes.
normalizations and omissions. Keep these claims separate, and retain the
version and coverage limits when quoting any result. This index is a source
and PR review; it does not constitute a new real-application or benchmark run.
## Additional feature records
These feature directories supplement the dated census above; this list does not
assert merge or verification status.
- [Saved values in browser scenarios](scenario-saved-values/spec.md)
- [Serve the calls agents make and the values applications count](write-call-values/spec.md)
- [Serve the writes callers make without recorded form fields](write-form-calls/spec.md)
- [Serve the writes that later reads explain](write-later-reads/spec.md)
- [Serve writes whose calls send different members](write-varied-calls/spec.md)
- [Serve sorted creates, listed references and toggles](write-sorts-references-toggles/spec.md)
@@ -1,5 +1,9 @@
# Serve an environment manifest as a replay environment
This specification records an implementation increment and its original problem
statement. For current behavior and limitations, see the
[current guide](../../../agent-environments.md).
Issue: https://github.com/morluto/rea/issues/4933
## Outcome
@@ -1,5 +1,9 @@
# Environment state view from captures
This specification records an implementation increment and its original problem
statement. For current behavior and limitations, see the
[current guide](../../../agent-environments.md).
Issue: https://github.com/morluto/rea/issues/4933
## Outcome
@@ -0,0 +1,56 @@
# Implementation plan
## Boundary and contract
Register `deno-standalone` in the existing artifact format owners:
`src/artifacts/artifactFormats.ts`, `ArtifactEmbeddedFormatProbes.ts`,
`ArtifactReader.ts`, `ArtifactReaderAdmission.ts`, `inventory/classify.ts`,
`inventory/scanReader.ts` and `extraction/ArtifactExtraction.ts`. Add the format
metadata and member roles to `src/domain/artifactFormatMetadata.ts`,
`artifactGraph.ts`, `artifactInspection.ts` and `evidenceSubject.ts`, and accept
the format in `src/contracts/artifactToolContracts.ts`. No new tool, provider or
bridge is added; the CLI and MCP changes are additive.
Split the layout into owners under `src/artifacts/deno/`, following Deno
`cli/lib/standalone/binary.rs` and `virtual_fs.rs` at 2.9.8 with libsui 0.16.4
section placement:
- `DenoStandaloneLocation.ts` confirms the carrier name before claiming a file.
It reads ELF and note headers, walks PE resource directories to the named
payload through `src/native/pe/PeResourceLayout.ts`, and scans Intel trailers
to the slice start so an enclosing app wins over a stored executable.
- `DenoSectionLayout.ts` parses metadata JSON, the virtual-filesystem header,
specifier, redirect and remote tables, and the npm snapshot length.
- `DenoVirtualFs.ts` walks directories, files and symlinks into safe logical
paths with indexed fallbacks, using `ArtifactPathRegistry.conflicts` in
`src/artifacts/ArtifactPaths.ts` to avoid occupied paths.
- `DenoStandaloneAdmission.ts` binds the located carrier to the admitted file.
`src/artifacts/DenoStandaloneArtifactReader.ts` projects members, metadata,
limitations and extraction regions through the existing stable artifact read and
safe output tree.
## Incremental work and validation
1. Define the format, member roles and contracts, preserving native inventory
for files with no confirmed carrier.
2. Implement carrier location for Mach-O, Intel trailer, ELF and PE, with
duplicate-section checks that reject unequal lengths before hashing.
3. Implement section parsing and the bounded virtual-filesystem walk with
indexed path fallbacks and remote specifier encoding.
4. Add the reader, inventory and extraction wiring with retained environment
and CA limitations.
5. Add synthetic layout, location, virtual-filesystem and reader tests, CLI
acceptance, filesystem boundary and MCP boundary tests.
6. Add `scripts/verify-deno-standalone.mjs` (`npm run verify:deno:standalone`)
for real Deno 2.9.8 host and cross-target compiles without execution.
7. Update the [usage guide](../../../deno-standalone.md), CLI guide, limits,
READMEs and skill references.
## Effects and compatibility
Inventory reads existing local files only; nothing is executed, injected or
downloaded. A `deno compile` executable that inventoried as a native binary now
reports `deno-standalone`, and a damaged section keeps the native format. There
is no runtime override for the named ceilings. Deno is a fixture producer for
the verifier only and is not installed by REA.
@@ -0,0 +1,58 @@
# Deno compile executable inventory and extraction
## Problem and outcome
`deno compile` embeds an application's metadata, virtual filesystem and remote
modules in a section of a native Mach-O, ELF or PE runtime. REA inventories such
a file as an ordinary native binary, so the embedded application stays hidden.
Let `inspect-artifact` / `inspect_artifact` report the file as root format
`deno-standalone` and `extract-artifact` write its embedded files through the
existing safe output tree, without running the executable or the Deno runtime.
## Requirements
- Recognize the Deno 2.9.8 / libsui 0.16.4 carriers: a Mach-O `__SUI` section
named `d3n0l4nd`, an Intel Mach-O `<~sui-data~>` trailer, an ELF `PT_NOTE` or
`SHT_NOTE` owned by `SUI` with type `0x53554901` and descriptor name
`d3n0l4nd`, and a PE `RT_RCDATA` resource named `D3N0L4ND`. Other layouts,
including older eszip trailers, are `unsupported`.
- Report root metadata: carrier, embedding, entry point, argv, V8 flags,
permission options, unstable configuration, application name, self-extracting
marker, virtual-filesystem case sensitivity and npm snapshot byte length. Keep
the compiler version unknown, because the metadata JSON has no version field.
- Report each virtual file as one occurrence with logical path, size and SHA-256,
and its transpiled output, CJS export analysis and source map as separate
occurrences with the same `index` and their own `role`.
- Keep logical paths safe and unique: unsafe, deep, colliding or over-long names
(255-byte component, 512-byte path, including `.deno-*` suffixes) use indexed
`deno-vfs/<index>` or `deno-remote/<index>` paths and retain the original
spelling when it fits the name allowance. Percent-encode colons, backslashes
and control characters in remote specifiers and keep the original in
`source_path`. Never follow symlink targets.
- Retain `Metadata.env_vars_from_env_file` values and `ca_data` bytes in local
Evidence with their counts and byte lengths, say so in the inventory
limitation, and do not write them as extracted files.
- Report a virtual filesystem that cannot be listed as `vfs_listing:
unsupported` with unknown coverage while remote modules still extract.
- Claim a file only after confirming the carrier name. A malformed table before
confirmation keeps the native inventory; a confirmed section that cannot be
parsed fails closed. Side-by-side trailers with different bytes fail closed.
- Bound metadata, header, table, specifier, remote body, virtual-filesystem
record, depth, retained-unit and retained-byte work with named allowances,
documented in [limits and recovery](../../../design/limits-and-recovery.md#deno-compile-sections).
## Acceptance
Synthetic fixtures cover every carrier, nested and side-by-side Intel trailers,
malformed and duplicate declarations, path indexing and encoding, unlistable
virtual filesystems, remote modules, npm snapshots and `ca_data`. Boundary tests
cover CLI inventory/extraction and MCP `inspect_artifact`. A real Deno 2.9.8
compile of the host and Linux, Windows and Intel macOS targets is inspected and
extracted by `npm run verify:deno:standalone` without running the output
([verification record](../../../verification/deno-standalone-2026-10-31.md)).
## Out of scope
Running the target, decoding npm snapshots, downloading remote modules,
withholding embedded environment values by default, and layouts other than Deno
2.9.8.
@@ -0,0 +1,10 @@
# Tasks
- [x] Define single-feature scope, contracts and implementation plan (`spec.md`, `plan.md`).
- [x] Register `deno-standalone` in the artifact format, inventory, extraction, domain and tool contract owners.
- [x] Implement carrier location for Mach-O sections, Intel trailers, ELF notes and PE resources in `src/artifacts/deno/DenoStandaloneLocation.ts`.
- [x] Implement bounded section parsing and the virtual-filesystem walk with indexed and percent-encoded logical paths.
- [x] Retain environment-file values and CA bytes in local Evidence with inventory limitations, and keep them out of extraction.
- [x] Add synthetic layout, location, virtual-filesystem and reader tests, CLI acceptance, filesystem boundary and MCP boundary tests.
- [x] Verify real Deno 2.9.8 host and cross-target compiles with `npm run verify:deno:standalone` ([record](../../../verification/deno-standalone-2026-10-31.md)).
- [x] Update the usage guide, CLI guide, limits, READMEs and skill references; pass documentation checks.
+24 -1
View File
@@ -1,11 +1,19 @@
# Desktop application environments
This roadmap records the planned implementation sequence. It does not establish
current completion, review approval or verification status. For current workflows,
see [desktop capture](../../desktop-application-capture.md),
[build computers](../../desktop-build-computer.md),
[tasks](../../desktop-application-tasks.md) and
[export](../../desktop-application-export.md). Individual verification records
retain their original scope and limitations.
Goal: REA turns an application installed and used on a Linux desktop into an
agent environment's computer application. The real application installs into
a computer image, launches to ready, exposes reset, load and get over its own
state, and ships with tasks graded through that state.
The work lands as one PR per step:
The planned sequence was one PR per step:
1. Pin the real agent environment lane to the framework release that carries
the computer application contract.
@@ -49,6 +57,21 @@ The work lands as one PR per step:
14. [XML text checks](xml-text-checks/spec.md): XML whose DOCTYPE only names
its DTD read as XML, starting with AbiWord, and checks of an element's
whole text across the runs an app splits a paragraph into.
15. [Download installs](download-installs/spec.md): applications no package
offers, from their project's AppImage or tarball pinned by URL and
SHA-256, unpacked under `/opt/rea-apps` by the build computer and the
export alike, starting with FreeCAD.
16. [Readers](file-readers/spec.md): checks of a file REA reads as binary,
such as GIMP's `.xcf` or Blender's `.blend`, through the app's own
headless command, run in the computer on a private copy of the file.
17. [Screen judges](screen-judge/spec.md): checks of state no file shows,
such as a calculator's result, by a model judging a screenshot against
the build's labelled seed and end screenshots.
18. [Secrets typed unseen](build-secrets/spec.md): a password or key the
person keeps in a file on the build host, typed by its handle, which no
result, log, record or exported bundle holds; sign-in and licence state
withheld from the seed and supplied at run time, seeded only with the
person's recorded consent; known handle values are checked explicitly.
Version 1 covers Linux with X11, applications whose state lives in files or
SQLite under the home directory, and real applications from public packages.
@@ -38,14 +38,14 @@ it for building, or from an existing bundle folder.
rather than its first package downloads.
- The control token never appears in a result, an error or a log; the helper's
stderr is redacted of it.
- Build bundle from a request: the app from the Ubuntu archive, an apt
repository with its key file, or a `.deb` URL with its SHA-256, dependencies
and architecture, rendered with the export's install shapes and Python
helpers; `Launch(at="demand")` through `gtk-launch`; no seed and no data
hooks. When the request sets `electron`, the install rewrites that desktop
entry's command with the export's launch policy (`--no-sandbox` right after
the program, unless the command already has it) before `gtk-launch`; REA in
a build-only layer, with Node.js 24.22.1 downloaded per
- Build bundle from a request: the app from the Ubuntu archive, with up to 16
extra archive packages beside it, an apt repository with its key file, or a
`.deb` URL with its SHA-256, dependencies and architecture, rendered with
the export's install shapes and Python helpers; `Launch(at="demand")` through
`gtk-launch`; no seed and no data hooks. When the request sets `electron`, the
install rewrites that desktop entry's command with the export's launch policy
(`--no-sandbox` right after the program, unless the command already has it)
before `gtk-launch`; REA in a build-only layer, with Node.js 24.22.1 downloaded per
architecture and checked, and REA's payload a parameter: a local archive
shipped in the environment folder (`REA_BUILD_COMPUTER_REA_ARCHIVE`) or,
later, a released download.
@@ -0,0 +1,29 @@
# Plan
1. Domain: `buildSecrets.ts` holds the handle schema, the value rules, the
spellings, `secretsIn` over bytes and a gzip file's inside, and
`redactSecrets` and `redactSecretsInJson` over text and JSON.
2. Host files: `BuildSecretFiles.ts` resolves the folder from the server's
environment, reads one handle's file under the ownership and permission
rules, and lists the handles the folder holds.
3. Typing: `computerActions.ts` adds `type_secret`, which `driverCall` maps to
`computer_type` with its handle; `DesktopBuildSecrets.ts` keeps the values
a server types and types one, shaping the result and refusals itself;
`DesktopBuildComputers.ts` logs the handle and sends the value.
4. Redaction: the action log, the witness record and the build tools'
registration redact each typed value.
5. Export: `DesktopBuildExport.ts` scans each fetched file before writing it
and refuses the bundle when one holds a secret.
6. Contract, skill, the build computer guide and this spec; unit tests for
the spellings and the files, and MCP boundary tests for typing, the
witness record and the export.
7. Withheld state: `appWithheld.ts` finds the files and names their
settings; `DesktopExportWithheld.ts` leaves them out of the seed, reads
them for the copy, and checks the consent; the class, `env.toml` and the
README declare them; the draft and the task admission leave them out.
8. Host: the capture passes the sign-in window, the files named and the
consents to the draft and the export, keeps the withheld files as
secrets, and supplies a bundle's settings at its start;
`record_build_consent` records the person's words.
9. Preserve values without inferring secrecy from their shape; only declared
handles and transport credentials are redacted.
@@ -0,0 +1,106 @@
# Secrets typed unseen
## Outcome
An agent building an environment for an app that asks for a password, a
licence key or a sign-in types it through REA without seeing it. The person
keeps the secret in a file on the build host; the agent names it by a handle;
REA types its value into the build computer. No tool result, action log,
witness record or exported bundle holds the value, and an export refuses a
bundle that does. The sign-in or licence state the app writes is withheld
from the bundle and supplied by whoever runs it, unless the person consents
to seed it. REA does not infer secrecy from a value or name.
## Requirements
- Secret files: one per handle, in `$XDG_CONFIG_HOME/rea/build-secrets/`, or
`~/.config/rea/build-secrets/` when `XDG_CONFIG_HOME` is unset or relative,
as the REA server's environment gives them. A handle is
`^[a-z0-9][a-z0-9._-]{0,62}$`. REA reads a handle's file when it types it
and refuses it unless the folder is a real folder, not a symbolic link, and
the file is a regular file, opened without following a link and without
blocking, owned by the server's user, with no group or other permission
bit, of at most one secret's size, and UTF-8. Its text, without one final
`\n` or `\r\n`, must hold 8 to 1024 characters and no control character.
A refusal names the file and the reason, never its text.
- `act_on_build_computer` action `type_secret`, taking only `secret`, a
handle, and refusing `screenshot`, `text` or any other field, and its
absence: REA sends `computer_type` with the value as `text`. Its result is
REA's own: `summary` `Typed the secret <handle>` and the driver's
`applied`, `delivery` and `others_since_frame`, one text block saying the
same, and no image. A driver refusal, or a call that fails, is REA's own
error naming the handle, without the driver's words or the cause, since
either could quote the value; a cancelled call stays a cancellation.
- Action log: a `type_secret` entry records `{"secret": "<handle>"}` and
counts as an input for the witness's edit and near miss, as `type` does.
Every string the log keeps, member names included, has each secret typed
on the server replaced by `<secret:<handle>>`.
- Results and records: every string in each build tool's text content and
structured content, errors included, and in `witness.json`'s record, has
each secret typed on the server, in each text spelling below, replaced by
`<secret:<handle>>`. Images pass as they are. After this server uses a
declared secret, automatic task drafting is withheld before it runs; the
capture remains available for a manually written task and export. Check
descriptions redact complete known values before shortening them. Ordinary
text is never redacted merely because it resembles part of a secret. The
host redacts the app's stderr and capture progress before quoting their end.
- Export scan: before writing a bundle on the host, REA searches each file's
path and bytes for every secret typed on the server and every other one the
folder holds, whatever its permissions, in these spellings: as it is,
escaped in JSON, UTF-16LE and UTF-16BE, lower- and upper-case hex of its
UTF-8, base64 in either alphabet of the characters that depend on the
value alone at each of the three byte alignments, and URL-encoded with
upper- or lower-case escapes and with `+` for a space; and the same inside
a gzip file, decompressed up to 64 MiB. A bundle holding one is refused as
an invalid request naming each secret's handle and the files, each value
in a file's name shown as `<secret:<handle>>`, and nothing is written to
the folder. A gzip file that expands past 64 MiB, which the scan cannot see inside, is refused by name when known secrets are checked.
- The skill asks the person for a secret's file instead of the secret, types
it only into a masked field, and stops when an export finds a secret.
- Withheld state: files under the owned paths that changed after checkpoint
`pre-sign-in` up to `post-sign-in`, by the capture's recorded changes, and
those `withhold` names, are withheld. With only one of the two checkpoints
the export is refused, and so is a window in which a walk, from
`pre-sign-in` to `post-sign-in`, stopped at its entry limit, could not list
a directory or check a path, or left a change unconfirmed, since it may
have missed a file the sign-in wrote. The draft leaves the withheld files
out and lists them as `withheld_files`; a task check naming one is
refused. An export is refused, too, for a dconf key of the app that the
window changed and the seed holds other than before it, since the class
seeds dconf keys and cannot withhold them, unless the withheld state is
seeded with consent. Each withheld file present at
the seed is left out of it and becomes a `SecretStr` field of the class's
`Settings`, named as Python takes an argument and distinct within the app,
which `env.toml`'s `[settings]` sets to `env:REA_<APP>_<FILE>`, so a
deploy without the variable is refused with its name. At first boot,
before `keep_initial`, the class writes each from its setting, the file's
bytes in base64, mode `0600`; `data/get` serves it neither as a part nor in
the views, and `data/reset` restores it. The README names each variable and
how to fill it. A file larger than 48 KiB is refused. The CLI copies the
withheld files to `--withheld-copy`, outside the bundle, and the build host
keeps each one's base64 as the secret `rea-<app>-<file>`, or the first
`rea-<app>-<file>-<n>` holding no other value (`0600`), never replacing a
secret file, named in the export's `withheld_files`.
- The export refuses a seed file whose bytes equal a withheld file's, by
SHA-256, naming both files; a backup that differs from the withheld file is
not caught, so the agent trashes backups before `seed`.
- Witness: `start_build_computer` from a bundle takes `settings`, each
`REA_*` variable mapped to a handle, whose value, up to 64 Ki characters,
REA puts in the deploy's environment only.
- Consent: `record_build_consent` keeps the person's words, kind `licence` or
`seed_sign_in`, with the computer, `source: "relayed"`. The export writes
every consent into the bundle's `consent.json`. `seed_sign_in: true` seeds
the withheld files instead, refused unless a `seed_sign_in` consent was
recorded; the CLI refuses `--seed-withheld` without one in `--consent`.
## Non-goals
- Redacting images: screenshots and the witness's recording show whatever
the screen shows, so a secret stays unseen only in a field that masks it.
- Finding a value inside a zip archive's compressed entries, or a token an
app derives from a secret, such as a session token after a sign-in.
- Keeping the secrets folder from the building agent's own shell on the same
host; the client's permission rules do that.
- Asking the person through the client itself: the agent relays their
words, so a consent is only as true as the agent's relay.
- Withholding state outside the owned paths, which the bundle never seeds.
@@ -0,0 +1,40 @@
# Tasks
- [x] Record the outcome, requirements and non-goals.
- [x] Handles, value rules, spellings, the scan and redaction in
`buildSecrets.ts` (secret files, export scan; `buildSecrets.test.ts`).
- [x] Read, list and keep a handle's file under the ownership and permission
rules (secret files; `BuildSecretFiles.test.ts`).
- [x] Type a secret by its handle with `type_secret`, REA shaping its result
and refusals (`type_secret`; `computerActions.test.ts`,
`buildSecretsMcp.test.ts`).
- [x] Redact typed values in the action log, the witness record and every
build tool result (action log, results and records;
`DesktopBuildActionLog.test.ts`, `buildWitness.test.ts`,
`buildSecretsMcp.test.ts`).
- [x] Scan the bundle for every secret before writing it, and refuse one
that holds any (export scan; `buildSecretsMcp.test.ts`).
- [x] Document the tools, the skill and the build computer guide.
- [x] Run the KeePassXC build, export and witness on an arm64 host and record
it in `verification.md`.
- [x] Withhold the sign-in window's files and those named: the class's
settings, `env.toml`, the README, the draft and the task admission
(withheld state; `appWithheld.test.ts`, `DesktopExportWithheld.test.ts`,
`ExportedAppPython.test.ts`).
- [x] Keep withheld files as secrets on the host, supply a bundle's settings
to its witness and record consent (withheld state, witness, consent;
`buildWithheldMcp.test.ts`).
- [x] Preserve unmarked token-shaped values and scan declared handles.
- [x] Run the KeePassXC and Typora withheld-state builds and record them in
`verification.md`.
- [x] Fix the review's gaps: refuse a sign-in window a walk may have missed a
change in, and dconf keys the window changed; refuse a gzip file too
large to check; keep each withheld file under a handle of its own; name
settings Python takes (withheld state, export scan;
`appWithheld.test.ts`, `DesktopExportWithheld.test.ts`,
`DesktopBuildSecrets.test.ts`, `buildSecretsMcp.test.ts`,
`buildWithheldMcp.test.ts`).
- [x] Withhold automatic drafting before it runs after a declared secret;
preserve the capture and manual task export. Redact full check values
before shortening descriptions, without matching partial secret prefixes.
@@ -0,0 +1,152 @@
# Verification
## Tests
- `src/domain/desktop/buildSecrets.test.ts`: handles; values too short, too
long or holding a control character; each spelling found, base64 at every
alignment in both alphabets and a gzip file's inside included; a near miss
and unrelated bytes not found; text and JSON redacted, member names too;
the start of a value each of REA's cuts leaves, a draft value's, a
reference's, a view's and a check's, hidden at any length and through an
XML or JSON escape, as a string, a JSON member and a result's JSON text;
ordinary text ending in `…`, such as `Please…`, left whole; an unclosed
quote before 64 KiB of escaped quotes scanned in linear time.
- `src/application/desktop/DesktopBuildOutputRead.test.ts`: a secret the
app's stderr or the capture's progress holds, redacted before the quote of
their end cuts it.
- `src/desktop/BuildSecretFiles.test.ts`: the folder from `XDG_CONFIG_HOME`
or `~/.config`; a `0600` or `0400` file read without its final line break;
a file others can read, a symbolic link, a linked folder, a missing file
and values it cannot type refused, no refusal quoting the value.
- `src/domain/desktop/computerActions.test.ts`, `buildWitness.test.ts` and
`src/application/desktop/DesktopBuildActionLog.test.ts`: `type_secret`
takes only `secret`, maps to `computer_type` and counts as an edit; the log
keeps the handle and redacts a typed value.
- `tests/boundary/mcp/buildSecretsMcp.test.ts`, over MCP with a fake driver:
the driver receives the value as `text` while no result holds it or an
image; `screenshot`, a file others can read and a missing file are
refused; a driver refusal quoting the value shows REA's words; a later
refusal quoting it shows the handle; `witness.json` records the handle and
a `type` holding the value redacted; and an export whose bundle holds a
secret's value is refused, naming its files with the value redacted, and
writes nothing, as is one holding a gzip file that expands past 64 MiB.
Each of these failed against the code before the change.
## KeePassXC on an arm64 build host
KeePassXC 2.7.6 from the Ubuntu 24.04 archive, on an arm64 Ubuntu 24.04 host
with agentenv-framework 0.9.1431 and a REA server whose `XDG_CONFIG_HOME`
held one `0600` file, `keepassxc-master`, with a made-up 30-character
password.
- Build computer: a new database's password and its confirmation were typed
with `type_secret`; each result read `Typed the secret keepassxc-master`
with `applied: "yes"`, and the screenshot afterwards showed 30 dots in each
field. `type_secret` with `screenshot: true` was refused. The database was
saved to `Documents/e-test.kdbx`, `seed` marked, a setting changed and
`end` marked.
- Export: with a second secret file holding `keepassxc`, a string the bundle
holds in its paths and files, the export was refused naming that handle
and ten files, `envs/<secret:e-probe>/env.toml` among them, and no folder
was written. With that file removed, the bundle of 10 files was written.
- Witness, in a computer of the bundle: the seeded database opened locked,
`type_secret` and Return unlocked it, and seed, after edit, near miss and
after reset all held. `witness.json` records the action as
`{"secret": "keepassxc-master"}`.
- Leaks: every request, result, the driver's and REA server's logs,
`witness.json`, the recording and the bundle (131 files) held the password
in none of the spellings the export searches, UTF-16 included; nor did
either computer's `docker logs` or any file in either container. A probe
file holding the password's hex and UTF-16 was found by the same scan.
## Withheld state and consent
The real-provider observations below predate removal of shape-based credential
classification. They describe that earlier build and do not verify current behavior.
### Tests
- `src/domain/desktop/appWithheld.test.ts`: the owned files changed in the
window, and those named; a window missing a checkpoint or out of order, or
one a walk may have missed a change in; a path outside the owned paths;
settings, variables and handles, a long path hashed and like paths kept
apart, and settings that are neither Python keywords nor alike in any
order.
- `src/application/desktop/DesktopExportWithheld.test.ts`: a withheld file
left out of the seed, declared a secret setting from `env:`, copied aside
and named in the README; seeding it refused without a consent and done with
one, `consent.json` shipped; a check on it refused; the draft leaving out
the window's files; dconf keys the window changed refused unless the seed
holds them as before it or they are seeded with consent.
- `src/application/desktop/DesktopBuildSecrets.test.ts`: a kept file's
handle that names a path refused, nothing written outside the folder.
- `src/desktop/BuildSecretFiles.concurrent.test.ts`: an export never given
the handle of another whose different bytes are still being written.
- `tests/boundary/application/buildExportGzipScans.test.ts`: a gzip seed
file decompressed once for its known-secret and size checks.
- `src/desktop/ExportedAppPython.test.ts`: `_write_withheld` writes the
decoded bytes `0600` and `_views` leaves the file out.
- `tests/boundary/mcp/buildWithheldMcp.test.ts`: the named file's bytes kept
as a `0600` secret and supplied to a witness's deploy by handle, a variable
other than `REA_*` refused; a later build's bytes kept under a handle of
their own, an earlier build's secret left as it was; consent recorded and
required for `seed_sign_in`, and the sign-in window passed to the draft and
the export; one sign-in checkpoint alone refused.
Each of these failed against the code before the change.
### KeePassXC on an arm64 build host
- Build: `pre-sign-in` marked, a database created with its password typed by
handle and saved, `post-sign-in` marked, which acknowledged
`Documents/e-test.kdbx` among its changes, then `seed`, a setting changed
and `end`. The draft listed `withheld_files: ["Documents/e-test.kdbx"]`,
and showed the KeeShare key KeePassXC generated as
`<credential:private-key>`.
- Export: refused with `seed_sign_in` and no consent. Without it, the seed
held only `keepassxc.ini`; `env.toml` set `documents_e_test_kdbx` to
`env:REA_KEEPASSXC_DOCUMENTS_E_TEST_KDBX`; agentenv's `_declare` read the
setting as a required `writeOnly` string; the README named the variable;
and the host kept the database's base64 as the `0600` secret
`rea-keepassxc-documents-e-test-kdbx`.
- Deploy without the variable: refused at the probe with
`Unresolved env:REA_KEEPASSXC_DOCUMENTS_E_TEST_KDBX reference`.
- Witness, from a copy of the bundle with `settings` naming that handle: the
computer wrote `Documents/e-test.kdbx`, mode `0600`, byte for byte the kept
file; the agent opened it and unlocked it with `type_secret`; seed, after
edit, near miss and after reset held, and the file was still there after
the reset.
- Leaks: no host file of the run but the secret's own, 146 in all, held the
password in any spelling; neither bundle held the database's bytes; and
neither computer's logs nor files held the password.
- The same build, export and witness ran again on the final code with a new
password: every stage held, and 124 host files, both bundles and both
computers held neither the password nor the database's bytes.
### Typora 1.14.9 on an arm64 build host
- Installed from `typora_1.14.9_arm64.deb` by URL and SHA-256, on its trial.
Its licence file was `~/.config/Typora/rXMW4iG3Bl`, hex of
`{"SLicense":""}`; it was `mAxvdiPNmi` on an amd64 host, so the name
differs by machine. Typora writes it at first launch, before any
checkpoint, so the export named it in `withhold`: it was left out of the
84-file seed, declared as `REA_TYPORA_CONFIG_TYPORA_RXMW4IG3BL`, and kept
as the secret `rea-typora-config-typora-rxmw4ig3bl`.
- Booted from the bundle's image with a made-up licence in the setting, the
initial state the class keeps before the app starts held the made-up file,
mode `0600`; Typora then found no valid licence and wrote an empty one over
the live file, which `data/reset` would put back.
- A witness through `start_build_computer` failed agentenv's first-boot
probe (`P4 a click in frame space hits its cell`), also for a bundle of the
same capture exported without withholding, so no stage ran.
## Limits of this verification
- Only a masked field was used: a field that shows its text shows a typed
secret in screenshots and in the recording.
- A deploy refused for want of a variable leaves agentenv's build of that
bundle failed; a later run needs `agent-env env build` or a fresh copy of
the bundle.
- The person's consent was relayed in a test; no person was asked.
@@ -28,23 +28,50 @@ and the recording and writes the record as Evidence.
out of every walk. A start returns once the capture reports the window
open; a refused or early-ended start stops the capture and reports its
output.
- `start_build_capture` takes `state_paths`, at most 16 files or folders in
the home, relative to it, after `~/` or absolute, without `..` and not the
home itself; the controller resolves each under the computer's home, both
as named and with its links followed (a path not there yet through its
nearest existing folder), refuses one outside it or in `~/.rea-build`
either way before launching anything, and passes each as named to the
capture as `--state-path`. A selected file is a document, or the app's own
state under a hidden folder of the home as named, before links, or when it
is a lock the app holds, such as LibreOffice's `.~lock.<name>#`.
- Acknowledgement: `capture-desktop-application` reports, beside each progress
message, an `event`: `window_open`; `checkpoint` with its name, trigger,
time, entries walked, changes and retained files and bytes, once it is
taken, the baseline, `stop` and `exit` included; and `checkpoint_refused`
with the reason. `mark_build_checkpoint` writes `checkpoint <name>` and
waits for the event naming it, returning its counts. Names follow a narrow
pattern, without the capture's own names; a name already taken is refused.
time, entries walked, changes and retained files and bytes, and up to ten
changed files, home-relative, those under a selected path first, then
those the app held open, caches and browser-engine storage last, with a count
of the rest, once it is taken, the baseline, `stop` and `exit` included;
and `checkpoint_refused` with the reason. `mark_build_checkpoint` writes
`checkpoint <name>` and waits for the event naming it, returning its counts
and changed files, both `null` when the REA in the computer predates them
and its event leaves them out. Names follow a narrow pattern, without the capture's own
names; a name already taken is refused.
- `stop_build_capture` sends `stop`, waits for the exit status, reads the
capture's Evidence and, when `seed` and `end` were acknowledged, runs
`describe-desktop-application-task --seed-checkpoint seed --end-checkpoint
end` and returns the changed files, their net change and suggested checks.
A draft with no files carries `notes`, coded `no_change`,
`unowned_changes` (up to five changed home paths with their roles, and a
count of the rest), `uncheckable_changes` (dconf databases whose app keys
were read and changed, which no check reads; a version kept without its
bytes is unreadable, not empty), `unreadable_changes` (dconf
databases that changed but could not be read, with the read `error`) and
`no_document`; a drafted file whose suggestions are thin carries one
naming its `file`, coded `by_position`, `view_state_only`, `long_text`,
`cut_view` or `unreadable_view`.
- `export_build_environment` writes the agent's task under `~/.rea-build`,
runs `export-desktop-application` with it and the same checkpoints into a
new folder there, reports a refused task with the export's own reason,
lists the bundle with sizes and SHA-256, fetches it through the driver's
`data/get` in answers of at most 8 MiB, checks each file and writes the
caller's new or empty folder through the safe output tree.
caller's new or empty folder through the safe output tree. The export
leaves lock files the app holds while it runs out of the seed, but never a
document or selected path, listing them in its limitations and README; a
start from a bundle whose computer never gets ready names the files its
seed holds by a profile lock's name, as a document lock or as a
`<file>.lck` beside a seeded file.
- `check_build_task` reads the one app's `data/get` through the card's
child URL, takes the state views beside its files and evaluates the task's
checks with `evaluateTaskChecks`, one result per check. With `stage`, the
@@ -106,6 +133,74 @@ and the recording and writes the record as Evidence.
fails on what the seed's view shows. The controller writes a folder's file
list to a file that REA reads through `data/get`, so a large bundle's list
is not cut at the 1 MiB of a command's output.
- Gaps of the build batches: an archive request takes up to 16
`extra_packages`, archive package names validated as its `package` is,
installed beside the app and listed in `start_build_computer`'s result
(a `.deb` request's `dependencies` are listed there too), for a runtime
piece the app needs that its package does not install (MyPaint's SVG icon
loader `librsvg2-common`, which GTK only recommends; a Java 17 for
Freeplane, whose launcher refuses noble's Java 21). The export takes them
as repeatable `--extra-package` and installs them beside the app, and the
build export passes them, and a `.deb` request's `dependencies` too, so a
`.deb` apt also offers no longer loses them when it is installed by name.
The limitations and the README name them, leaving out only what the
bundle installs anyway: the app's own package and, when it is installed
from its `.deb`, the dependencies the `Packages` line names. A package the
captured `.deb` lists only as one alternative stays, since apt may pick
another, such as `openjdk-17-jre | java-runtime`.
- Gaps of the third batch's GnuCash build: the build bundle installs
`dconf-cli`, so the capture reads the app's dconf settings, such as
GnuCash's "Show tips at startup" unticked before `seed`, and the seed
keeps them; an export whose dconf database changed by the seed but could
not be read names it, with the read error, in its limitations. A
`<file>.lck` or `<file>.LCK` beside a file the capture recorded in the
same folder, as GnuCash's `household.gnucash.LCK`, is a lock left out of
the seed; a lone `notes.lck` is seeded.
- Gaps of the fourth batch: a desktop entry that is not reverse-DNS names
the environment whole, without a trailing version, so `glabels-3.0` gives
`glabels` rather than `0`, in the build computer and the export alike. The
capture launches the app with `LIBC_FATAL_STDERR_=1`, so a glibc abort's
reason reaches the app-exit error. A `.<file>.lock` or `.<file>.lck` beside
its file, as Grisbi's `.household.gsb.lock`, is a lock too, left out of the
seed and its text seeds; a lone `.notes.lock` is seeded. A seeded
LibreOffice `registrymodifications.xcu` ships without its `RecoveryList`
items, which started an Impress bundle into document recovery, and a
limitation and the README name the file. A checkpoint ranks caches and
browser-engine storage last under a selected folder too, unless named
themselves, so LibreOffice's icon cache no longer fills `changed_files`.
- Gaps of the fifth batch: a checkpoint names first the files the app's
window titles have named so far, which the session now hands each
checkpoint, so a document saved and no longer held open (Gnumeric, LyX,
Tiled) leads; then files selected themselves; then those held open, under
a selected folder or in state directories; then the rest; then caches and
browser storage, which now include a whole `QtWebEngine` profile and
Chromium's `Visited Links`, `Platform Notifications` and `user_prefs.json`.
Example prompts name the app, and the export's limitations say when a
task's prompt names neither the app's title, environment nor package: a
solving agent's shell cannot see the computer's files. The unowned paths
limitation counts files or folders.
- Gaps of the published bundles: app-state logs are retained because their
names alone do not distinguish diagnostic output from user history or
database writes. Locks remain excluded under the lock ownership rules.
LibreOffice's recovery list items are found with the shared XML parser and
cut by their source ranges, so quoting, spacing, comments and CDATA cannot fool the match,
and a registry that is not well-formed ships unchanged.
- Gaps of the seventh batch: a window title names a file only by its whole
name, or its `~/` or absolute path, never by a folder of a path it shows,
and an extensionless name only standing alone; files under `~/.cache` and
dconf's databases are never named. CherryTree's title, which shows
`/home/user/Documents`, made `~/.cache/dconf/user` a second document, so
its bundle opened none; the state role and the checkpoint ranking share
the fix. VYM's `<map>.vym.lock` beside the map is a lock too, while a
project's `Gemfile.lock` beside its `Gemfile` stays seeded.
- Gaps of the eighth batch (Poedit): a `*.lock` or `*.lck` directly in the
home and Lucene's `write.lock` anywhere are locks; a lock or log never
becomes an owned path, is never named among the unowned paths, and makes
no folder count as held open, so neither the capture nor the export points
`state_paths` at the home. A seed file keeps its permission bits at the
seed where the capture recorded them, through the module's `SEED_MODES`,
so a `0600` file an app checks boots `0600`; a file the capture never saw
change has no recorded mode.
- The witness reads the build computer's bounded action log: its stage rules
use the log's count and the last applied action of each kind, and the
record holds the entries the log keeps, `actions_dropped`, and a
Loaded 100 of 914 files, more files were not shown because too many files have changed in this diff. Show more