diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json new file mode 100644 index 0000000000..181e6d284a --- /dev/null +++ b/.agents/plugins/marketplace.json @@ -0,0 +1,21 @@ +{ + "name": "rea", + "interface": { + "displayName": "REA" + }, + "plugins": [ + { + "name": "rea", + "source": { + "source": "npm", + "package": "rea-agents", + "version": "6.8.0" + }, + "policy": { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "Developer Tools" + } + ] +} diff --git a/.agents/skills/reverse-engineer-anything/SKILL.md b/.agents/skills/reverse-engineer-anything/SKILL.md index 901195fb68..da4f30b46f 100644 --- a/.agents/skills/reverse-engineer-anything/SKILL.md +++ b/.agents/skills/reverse-engineer-anything/SKILL.md @@ -17,6 +17,9 @@ readiness or provider commands. Installing this skill supplies instructions; it does not register the REA MCP server, install analysis engines, or add tools to an already-running agent. +The exception is a Claude Code or Codex plugin install: the plugin bundles +this skill and registers its own `rea` server, outside the state that +`rea setup` and `rea doctor` manage. If REA tools are available and their registration is not known to be stale, proceed directly to the target. Do not run diagnostics or setup before every @@ -37,37 +40,18 @@ repeat or known not to have started. If it may already have changed the target, or it fails again, tell the user and ask them to restart the MCP client. If REA could not start its connection, retry once, then tell the user and ask them to restart the MCP client. Do not retry a startup failure that -returns the same unchanged result. Run `rea doctor` when REA could not start +returns the same unchanged result. For plugin installs, follow +[plugin recovery](references/connection-and-recovery.md#rea-installed-as-a-client-plugin). +For setup-owned registrations, run `rea doctor` when REA could not start or tools stay missing after that restart. For `cleanup_incomplete`, a retryable capacity limit, or `configuration_invalid`, follow the recovery guide's ladder before asking for a restart. Read that guide before a second repair attempt. -1. Diagnose without changing REA or client configuration. `npx` may download - the package and write to npm's cache. For Codex, run - `npx -y rea-agents@latest doctor --client codex --json`. Substitute the current - supported client: `claude_code`, `claude_desktop`, `codex`, `cursor`, - `gemini_cli`, `windsurf`, `devin`, `opencode`, `antigravity`, `copilot_cli`, - `commandcode`, `vscode`, `grok_build`, `omp`, or `grok_bot`. `grok_bot` has no local - file registration: doctor reports the Grok Bot chat step, and setup does not - write `mcp.json`. If the client is unknown, use `doctor --json` and - inspect its registration results before choosing a setup scope. -2. Distinguish the reason. Missing, malformed, or stale registration needs a - scoped configuration repair. An aligned registration with no tools in the - active session needs a restart/reconnection; doctor cannot prove that the - current agent has connected. A missing provider affects only tasks requiring - that provider: static JavaScript inspection needs neither Hopper nor Ghidra, - and Android inspection has separate bring-your-own JADX/Java prerequisites. -3. For a configuration repair, prepare the read-only plan: - `npx -y rea-agents@latest setup --client codex --dry-run --json`. - Use the current client's ID, show its exact proposed paths, backups, and - changes, and obtain approval before setup writes configuration or installs - Hopper. Setup normally installs the matching bundled skill too; include that - replacement in the reviewed plan. After approval, apply the same scope with - `npx -y rea-agents@latest setup --client codex --yes`. Add `--install-hopper` - only if that separate installation was needed and explicitly approved. -4. Restart/reconnect the affected agent. Verify that REA tools actually appear - in the session, then resume the original investigation. If they remain - absent, inspect the client's MCP launch error rather than repeating setup. +Choose the installation owner before repairing registration. Plugin installs use +[plugin recovery](references/connection-and-recovery.md#rea-installed-as-a-client-plugin); +only setup-owned registrations use the guide's +[registration repair plan](references/connection-and-recovery.md#repair-registration-when-needed). +A plugin-only doctor result of `missing` does not call for `rea setup`. REA setup never installs or upgrades Node.js, npm, Homebrew, Java, Ghidra, IDA, JADX, Kuna, Binwalk, or Unblob. Use existing prerequisites; do not install unrelated @@ -86,7 +70,7 @@ returns the Evidence record directly. This fallback does not establish that MCP is configured. Native CLI tasks still require their selected engine. Prefer an existing `rea` CLI. When none is installed and REA package acquisition is within the authorized scope, use `npx -y rea-agents@latest` in its place. -Configuration repair starts with a read-only setup plan; show paths, backups and +For setup-owned registration, configuration repair starts with a read-only setup plan; show paths, backups and skill replacement before applying authorized changes. Preserve existing approval and target-execution boundaries. diff --git a/.agents/skills/reverse-engineer-anything/references/android-applications.md b/.agents/skills/reverse-engineer-anything/references/android-applications.md index e1e324b51d..cc51e22afe 100644 --- a/.agents/skills/reverse-engineer-anything/references/android-applications.md +++ b/.agents/skills/reverse-engineer-anything/references/android-applications.md @@ -13,6 +13,27 @@ own APK path and explicit selectors; do not open a native session first. Choose an `overload_index` from the class inventory when methods are ambiguous instead of guessing. +For JNI implementations, discover `inspect_android_jni_bindings`. Select raw +DEX class/method identities and optional descriptors, ABI or logical library +paths. Prefer `detail: "summary"`; complete Evidence remains retained and +`android-jni` views page declarations, libraries, candidates or binding rows +with exact fields. Global native-pair ambiguity survives class selection. +Preserve slot/relocation provenance and source coverage: matched means observed +candidate presence; partial scans do not establish uniqueness or absence. +This reads DEX/ELF bytes without loading the APK into the decompiler or executing +target code. Runtime registration and loading remain unknown. See the +[JNI guide](https://github.com/morluto/rea/blob/main/docs/android-analysis.md#link-native-declarations-to-jni-candidates). + +For an R8/ProGuard release build with its `mapping.txt`, pass the absolute +`mapping_path` to `inspect_android_class` or `inspect_android_method`. Prefer +`detail: "summary"` to receive normalized symbols or the selected body without +duplicate raw class metadata. Complete Evidence stays retained under the linked +parent ID and can be exported; CLI summary delivery requires `--evidence_output`. +Omitted or complete detail preserves the full inline response. Keep +selecting by observed names; the separate `mapping` block reports each symbol +as `mapped`, `ambiguous` or `unmapped` after checking DEX types and prototypes. +REA does not verify that the mapping belongs to the APK build. + The provider requires a separately supplied headless JADX MCP JAR 0.7.1 and Java 17 or newer. `REA_JADX_MCP_JAR` selects the absolute JAR path; `JAVA_HOME` can select Java. Use `rea doctor --provider jadx --json` to check the JADX diff --git a/.agents/skills/reverse-engineer-anything/references/connection-and-recovery.md b/.agents/skills/reverse-engineer-anything/references/connection-and-recovery.md index 102f2abda4..7abd414917 100644 --- a/.agents/skills/reverse-engineer-anything/references/connection-and-recovery.md +++ b/.agents/skills/reverse-engineer-anything/references/connection-and-recovery.md @@ -17,7 +17,7 @@ does not establish which server an approval wildcard covers. See | Observation | Meaning and next step | | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| No REA tools in the active session | Inspect registration with `rea doctor --client codex --json`. A skill installation alone does not register MCP. | +| No REA tools in the active session | If REA was installed as a client plugin, follow the plugin section below. Otherwise inspect registration with `rea doctor --client codex --json`. A skill installation alone does not register MCP. | | Missing, malformed or stale registration | Prepare a scoped setup plan; apply only authorized changes with backups. | | Aligned registration, but no connected tools | Restart/reconnect the client. Doctor checks registration; it cannot establish the current agent's connection. Inspect the client's launch error if reconnection fails. | | MCP connection dropped or REA could not start | If the connection drops, retry that call once only when it is safe to repeat or known not to have started. If it may already have changed the target, or the same failure returns, tell the user REA's connection failed and ask them to restart the MCP client. If REA could not start its connection, retry once, then tell the user and ask them to restart the MCP client. Do not retry a startup failure that returns the same unchanged result. Run `rea doctor` when REA could not start or tools stay missing after restart. Doctor cannot restore a live connection by itself. | @@ -116,6 +116,32 @@ is not a recommendation to change it. Do not invent a setting. Host memory and - `invalid_request`: correct the reported fields from the current schema. Do not repeat the unchanged call. +## REA installed as a client plugin + +A Claude Code or Codex plugin owns its `rea` server and this skill. Doctor's +`--client` and `--skill` checks and `rea setup` read and write only +setup-owned state, so for a plugin-only install they report `missing`, and +applying setup would add a second `rea` server. If this skill was loaded from +a plugin, or the client lists a `rea` plugin, do not prepare a setup plan for +missing tools. Instead: + +- Check that the plugin is installed and enabled with the client's own + listing: `claude plugin list` and `/mcp` in Claude Code, `codex plugin list` + in Codex. +- Restart or reconnect the client, then read its launch error for the `rea` + server if tools are still absent. The plugin starts its bundled runtime; a missing build or version mismatch + requires a reinstall, or a fresh build when developing from source. +- Check analysis engines through the connected server's + `binary_session.result.tool_availability`. `rea doctor --provider --json` + from a shell reports that shell's environment, which can differ from the + environment the client gave the plugin server. If you still run it through + the package runner, use the version pinned in the plugin manifest's server + entry (`rea-agents@`), not `@latest`, so it matches the server the + plugin starts. + +Use the setup repair below only when the user wants a setup-owned registration +instead of the plugin, and remove or disable the plugin first. + ## Repair registration when needed For Codex: diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json new file mode 100644 index 0000000000..d5f55d4387 --- /dev/null +++ b/.claude-plugin/marketplace.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://anthropic.com/claude-code/marketplace.schema.json", + "name": "rea", + "description": "Reverse engineer anything with agents, from app behavior down to native binaries.", + "owner": { + "name": "morluto", + "url": "https://github.com/morluto" + }, + "plugins": [ + { + "name": "rea", + "description": "Reverse engineer anything from your terminal or agent with one CLI and MCP server.", + "source": { + "source": "npm", + "package": "rea-agents", + "version": "6.8.0" + }, + "category": "development" + } + ] +} diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000000..6f3772482e --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,28 @@ +{ + "name": "rea", + "version": "6.8.0", + "description": "Reverse engineer anything from your terminal or agent with one CLI and MCP server.", + "author": { + "name": "morluto", + "url": "https://github.com/morluto" + }, + "homepage": "https://rea.tools/", + "repository": "https://github.com/morluto/rea", + "license": "MIT", + "keywords": [ + "reverse-engineering", + "binary-analysis", + "decompiler", + "mcp-server" + ], + "skills": "./skills", + "mcpServers": { + "rea": { + "command": "node", + "args": [ + "${CLAUDE_PLUGIN_ROOT}/scripts/plugin-mcp-launcher.mjs", + "6.8.0" + ] + } + } +} diff --git a/.codex-plugin/mcp.json b/.codex-plugin/mcp.json new file mode 100644 index 0000000000..718c42503b --- /dev/null +++ b/.codex-plugin/mcp.json @@ -0,0 +1,13 @@ +{ + "mcpServers": { + "rea": { + "command": "node", + "args": [ + "./scripts/plugin-mcp-launcher.mjs", + "6.8.0" + ], + "cwd": ".", + "startup_timeout_sec": 30 + } + } +} diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json new file mode 100644 index 0000000000..9246cbed5f --- /dev/null +++ b/.codex-plugin/plugin.json @@ -0,0 +1,38 @@ +{ + "name": "rea", + "version": "6.8.0", + "description": "Reverse engineer anything from your terminal or agent with one CLI and MCP server.", + "author": { + "name": "morluto", + "url": "https://github.com/morluto" + }, + "homepage": "https://rea.tools/", + "repository": "https://github.com/morluto/rea", + "license": "MIT", + "keywords": [ + "reverse-engineering", + "binary-analysis", + "decompiler", + "mcp-server" + ], + "skills": "./skills", + "mcpServers": "./.codex-plugin/mcp.json", + "interface": { + "displayName": "REA", + "shortDescription": "Reverse engineer anything with agents", + "longDescription": "Use REA to explain shipped behavior from native binaries, managed assemblies, Electron and JavaScript bundles, packages, firmware, and browser targets, with evidence that separates observations from inferences.", + "developerName": "morluto", + "category": "Developer Tools", + "capabilities": [ + "Interactive", + "Read", + "Write" + ], + "websiteURL": "https://rea.tools/", + "defaultPrompt": [ + "Use REA to explain how this binary implements a feature.", + "Use REA to compare two versions of this application.", + "Use REA to recover the sources from this JavaScript bundle." + ] + } +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ec1acc5600..5d6ccd85e8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -855,6 +855,24 @@ jobs: # The matching native artifact establishes real Job Object and private # runtime boundaries for these fixtures. Ghidra and Java are not needed; # real engine claims remain in the separate controlled-provider workflow. + # Run native proofs before the broad curated suite so an unrelated + # fixture failure cannot hide the real control and recovery checks. + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: windows-process-boundary-fixture + path: .cache/windows-process-boundary/ + # Passing the fixture adds the breakaway, caller/child token, environment + # semantics and ancestor reparse observations, which the lane skips + # entirely when it is absent. + - run: >- + npm run verify:windows-native -- . + "${{ github.workspace }}\.cache\windows-process-boundary\process-boundary.exe" + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: windows-native-inspection-fixture + path: .cache/windows-native-inspection-fixture/ + - name: Verify native inspection failure ownership and recovery + run: node scripts/verify-windows-native-inspection.mjs - name: Run curated Windows capability tests run: >- npx vitest run --coverage.enabled=false @@ -907,22 +925,6 @@ jobs: tests/process-global/runnerCancellation.test.ts tests/process-global/windowsOwnedCommand.test.ts tests/conformance/providers/ghidra/realGhidraWindowsWorkflow.test.ts - - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - with: - name: windows-process-boundary-fixture - path: .cache/windows-process-boundary/ - # Passing the fixture adds the breakaway, caller/child token, environment - # semantics and ancestor reparse observations, which the lane skips - # entirely when it is absent. - - run: >- - npm run verify:windows-native -- . - "${{ github.workspace }}\.cache\windows-process-boundary\process-boundary.exe" - - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - with: - name: windows-native-inspection-fixture - path: .cache/windows-native-inspection-fixture/ - - name: Verify native inspection failure ownership and recovery - run: node scripts/verify-windows-native-inspection.mjs - name: Verify real Node Inspector discovery and observation timeout-minutes: 10 env: diff --git a/.gitignore b/.gitignore index e4dc408141..5de43472a9 100644 --- a/.gitignore +++ b/.gitignore @@ -50,7 +50,7 @@ Thumbs.db # Local reference sources and analysis artifacts /_reference/ -/experiments/analysis-efficiency/results/ +/experiments/analysis-efficiency/ # Generated website download /website/public/examples/notes-example.zip diff --git a/.oxfmtrc.json b/.oxfmtrc.json index 633bd7bc36..153091c943 100644 --- a/.oxfmtrc.json +++ b/.oxfmtrc.json @@ -10,7 +10,10 @@ "node_modules/**", "CHANGELOG.md", "package-lock.json", + ".claude-plugin/plugin.json", + ".codex-plugin/plugin.json", "_reference/**", - "third_party/**" + "third_party/**", + ".codex-plugin/mcp.json" ] } diff --git a/README.md b/README.md index b0666cdd45..07af6c4d1e 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ configuration. Restart your agent afterward. Setup supports Claude Code, Codex, Cursor, Gemini CLI, Grok Build and [other agents](docs/installation.md#supported-agents). See [installation and setup](docs/installation.md) for provider configuration and -manual MCP registration. +manual MCP registration and Claude Code/Codex plugin installation. MCP uses compact input schemas by default to reduce context overhead. Set `REA_MCP_INPUT_SCHEMA_PROFILE=full` in your MCP registration when you need the diff --git a/bridge/android/ReaJadxBridge.java b/bridge/android/ReaJadxBridge.java index 120c62b1ef..09d0d6004e 100644 --- a/bridge/android/ReaJadxBridge.java +++ b/bridge/android/ReaJadxBridge.java @@ -1,5 +1,9 @@ import com.atxx.jhmcp.*; import com.google.gson.*; +import com.android.tools.smali.dexlib2.Opcodes; +import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile; +import com.android.tools.smali.dexlib2.dexbacked.DexBackedClassDef; +import com.android.tools.smali.dexlib2.dexbacked.DexBackedMethod; import io.modelcontextprotocol.kotlin.sdk.server.*; import io.modelcontextprotocol.kotlin.sdk.types.*; import jadx.api.*; @@ -9,14 +13,21 @@ import jadx.api.plugins.input.data.ICodeReader; import jadx.api.plugins.input.data.IMethodRef; import jadx.api.plugins.input.insns.InsnIndexType; import jadx.api.plugins.input.insns.Opcode; +import jadx.core.codegen.TypeGen; import jadx.core.dex.info.MethodInfo; import jadx.core.dex.nodes.*; import java.io.PrintStream; import java.io.StringReader; +import java.io.InputStream; +import java.io.IOException; +import java.nio.file.Path; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.concurrent.CountDownLatch; import java.util.stream.Collectors; +import java.util.zip.CRC32; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; import kotlin.Unit; import kotlin.ResultKt; import kotlin.coroutines.Continuation; @@ -178,6 +189,205 @@ class ReaJadxBridge { manifestSnapshot = null; } + // One bounded DEX at a time, beside the already admitted analysis JVM. The + // response allowance accounts for worst-case JSON escaping before retention. + private static final int NATIVE_DEX_BYTES = 64 * 1024 * 1024; + private static final long NATIVE_TOTAL_DEX_BYTES = 256L * 1024 * 1024; + // This JSON is escaped again inside an 8 MiB MCP frame. + private static final long NATIVE_JSON_BYTES = 4L * 1024 * 1024; + + /** The bundled decoder allocates its declared UTF-16 length before validating bytes. */ + private static final class NativeDex extends DexBackedDexFile { + private OptionalIndexedSection boundedStrings; + NativeDex(byte[] bytes) { super(Opcodes.getDefault(), bytes); } + + @Override public OptionalIndexedSection getStringSection() { + if (boundedStrings == null) { + var source = super.getStringSection(); + boundedStrings = new OptionalIndexedSection<>() { + @Override public int size() { return source.size(); } + @Override public int getOffset(int index) { return source.getOffset(index); } + @Override public String getOptional(int index) { return index == -1 ? null : get(index); } + @Override public String get(int index) { + int offset = getBuffer().readSmallUint(source.getOffset(index)); + int units = getDataBuffer().readerAt(offset).readSmallUleb128(); + if (units > NATIVE_JSON_BYTES / 6 + || units > getDataBuffer().getBuf().length - offset) + throw new IllegalArgumentException("DEX string exceeds the native decoding allowance"); + return source.get(index); + } + }; + } + return boundedStrings; + } + } + + private static void checkNativeInterrupted() { + if (Thread.currentThread().isInterrupted()) + throw new java.util.concurrent.CancellationException("Native declaration inventory interrupted"); + } + + private static final class NativeInventory { + final List> methods = new ArrayList<>(); + final List unknowns = new ArrayList<>(); + long retainedBytes = 1024; + int dexEntries; + int examinedDexEntries; + int examinedClasses; + int examinedMethods; + boolean partial; + boolean diagnosticLimit; + + void unknown(String reason) { + partial = true; + long bytes = 64L + reason.length() * 6L; + if (unknowns.size() < 16 && retainedBytes + bytes <= NATIVE_JSON_BYTES - 4096) { + unknowns.add(reason); + retainedBytes += bytes; + } else if (!diagnosticLimit) { + diagnosticLimit = true; + unknowns.add("Additional native-inventory limitations exceed the retained diagnostic allowance."); + } + } + + boolean retain(Map method, long bytes) { + if (retainedBytes + bytes > NATIVE_JSON_BYTES - 4096) { + unknown("Native declarations exceed the 4 MiB retained JSON allowance; remaining declarations are unknown."); + return false; + } + retainedBytes += bytes; + methods.add(method); + return true; + } + + Map result() { + return Map.of("scope", "apk-root-dex-declarations", "methods", List.copyOf(methods), + "coverage", Map.of("status", partial ? "partial" : "complete", + "dex_entries", dexEntries, "examined_dex_entries", examinedDexEntries, + "examined_classes", examinedClasses, "examined_methods", examinedMethods), + "unknowns", List.copyOf(unknowns)); + } + } + + /** Match Android's standard root multidex carriers, without a basename guess. */ + private static boolean nativeDexEntry(String name) { + return name.equals("classes.dex") || name.matches("classes[0-9]+\\.dex"); + } + + private static byte[] readNativeDex(ZipFile archive, ZipEntry entry) throws IOException { + long size = entry.getSize(); + if (size < 0 || size > NATIVE_DEX_BYTES) + throw new IllegalArgumentException("DEX exceeds the 64 MiB single-member read allowance"); + byte[] bytes = new byte[(int) size]; + CRC32 crc = new CRC32(); + try (InputStream input = archive.getInputStream(entry)) { + int offset = 0; + while (offset < bytes.length) { + checkNativeInterrupted(); + int read = input.read(bytes, offset, Math.min(65536, bytes.length - offset)); + if (read < 0) throw new IOException("DEX is shorter than its ZIP declaration"); + if (read == 0) continue; + crc.update(bytes, offset, read); + offset += read; + } + if (input.read() != -1) throw new IOException("DEX exceeds its ZIP declaration"); + } + if (entry.getCrc() < 0 || entry.getCrc() != crc.getValue()) + throw new IOException("DEX does not match its ZIP CRC32 declaration"); + return bytes; + } + + /** Raw DEX ownership precedes JADX's duplicate-class selection and aliases. */ + static Map nativeDeclarations(Path apk) { + NativeInventory inventory = new NativeInventory(); + try (ZipFile archive = new ZipFile(apk.toFile())) { + Map names = new HashMap<>(); + var directory = archive.entries(); + while (directory.hasMoreElements()) { + checkNativeInterrupted(); + ZipEntry entry = directory.nextElement(); + if (!entry.isDirectory() && nativeDexEntry(entry.getName())) { + inventory.dexEntries++; + names.merge(entry.getName(), 1, Integer::sum); + } + } + long totalBytes = 0; + int entryIndex = -1; + directory = archive.entries(); + while (directory.hasMoreElements()) { + checkNativeInterrupted(); + ZipEntry entry = directory.nextElement(); + entryIndex++; + String path = entry.getName(); + if (entry.isDirectory() || !nativeDexEntry(path)) continue; + if (names.get(path) != 1) { + inventory.unknown("Duplicate root DEX entry name cannot be selected uniquely by the ZIP reader: " + path); + continue; + } + if (entry.getSize() < 0 || entry.getSize() > NATIVE_DEX_BYTES + || entry.getSize() > NATIVE_TOTAL_DEX_BYTES - totalBytes) { + inventory.unknown("Root DEX member exceeds the 64 MiB member or 256 MiB total read allowance: " + path); + continue; + } + totalBytes += entry.getSize(); + try { + DexBackedDexFile dex = new NativeDex(readNativeDex(archive, entry)); + var classes = dex.getClassSection(); + for (int classIndex = 0; classIndex < classes.size(); classIndex++) { + checkNativeInterrupted(); + DexBackedClassDef cls = classes.get(classIndex); + String type = cls.getType(); + if (!type.startsWith("L") || !type.endsWith(";")) + throw new IllegalArgumentException("Class definition has no reference type"); + String className = type.substring(1, type.length() - 1).replace('/', '.'); + // Passing false retains duplicate encoded method references too. + for (Iterable group : List.of( + cls.getDirectMethods(false), cls.getVirtualMethods(false))) { + for (DexBackedMethod method : group) { + checkNativeInterrupted(); + inventory.examinedMethods++; + if ((method.getAccessFlags() & 0x100) == 0) continue; + String methodName = method.getName(); + String returnType = method.getReturnType(); + long characters = 2L + returnType.length(); + for (CharSequence parameter : method.getParameterTypes()) { + characters += parameter.length(); + if (characters * 6L > NATIVE_JSON_BYTES) break; + } + long bytes = 512L + 6L * (className.length() + methodName.length() + + path.length() + characters); + if (inventory.retainedBytes + bytes > NATIVE_JSON_BYTES - 4096) { + inventory.unknown("Native declarations exceed the 4 MiB retained JSON allowance; remaining declarations are unknown."); + return inventory.result(); + } + StringBuilder descriptor = new StringBuilder((int) characters).append('('); + for (CharSequence parameter : method.getParameterTypes()) descriptor.append(parameter); + descriptor.append(')').append(returnType); + Map row = Map.of("source_index", inventory.methods.size(), + "class_name", className, "method_name", methodName, "descriptor", descriptor.toString(), + "dex_entry", path, "dex_entry_index", entryIndex, "class_index", classIndex, + "method_index", method.getMethodIndex()); + if (!inventory.retain(row, bytes)) return inventory.result(); + } + } + inventory.examinedClasses++; + } + inventory.examinedDexEntries++; + } catch (IOException | RuntimeException failure) { + if (failure instanceof java.util.concurrent.CancellationException) throw (RuntimeException) failure; + inventory.unknown("Root DEX native declarations could not be fully read from " + path + ": " + + failure.getClass().getSimpleName() + + (failure.getMessage() == null ? "" : " (" + failure.getMessage() + ")")); + } + } + } catch (IOException failure) { + // A failed archive close must fail the operation so the provider retires + // its owned JVM; do not cache a result with lost file-resource ownership. + throw new IllegalArgumentException("APK ZIP native declaration inventory could not finish its reader", failure); + } + return inventory.result(); + } + /** Original archive identity, never a deobfuscated basename or name suffix. */ private ManifestSnapshot manifest(JadxSession current) { if (manifestSession != current || manifestSnapshot == null) { @@ -270,7 +480,7 @@ class ReaJadxBridge { .map(Object::toString).collect(Collectors.joining(", ")) + "): " + method.getReturnType().toString(); return new MethodSnapshot(name, rawName, shortId, List.copyOf(bodyAbsenceMarkers), Map.of( - "name", name, "signature", signature, + "name", name, "raw_name", rawName, "signature", signature, "dex_descriptor", descriptor, "is_constructor", method.isConstructor(), "def_pos", 0)); }).toList(); @@ -280,8 +490,11 @@ class ReaJadxBridge { List> valuedFields = new ArrayList<>(); boolean anyValue = false; for (FieldNode field : orderedFields) { + // Raw DEX identity for mapping lookups; the display type can carry generics. Map entry = Map.of("name", field.getAlias(), - "type", field.getType().toString(), "def_pos", 0); + "raw_name", field.getFieldInfo().getName(), + "type", field.getType().toString(), + "dex_type", TypeGen.signature(field.getFieldInfo().getType()), "def_pos", 0); fields.add(entry); Map value = dexStaticValue(field); if (value == null) valuedFields.add(entry); @@ -293,10 +506,11 @@ class ReaJadxBridge { } } List inner = node.getInnerClasses().stream().map(ClassNode::getFullName).toList(); + List innerRaw = node.getInnerClasses().stream().map(ClassNode::getRawName).toList(); Map summary = Map.of( "full_name", cls.getFullName(), "raw_name", cls.getRawName(), "name", cls.getName(), "method_count", methods.size(), "field_count", fields.size(), - "inner_class_count", inner.size(), "inner_classes", inner, + "inner_class_count", inner.size(), "inner_classes", inner, "inner_class_raw_names", innerRaw, "methods", methods.stream().map(MethodSnapshot::summary).toList(), "fields", List.copyOf(fields)); // DEX static values are opt-in, so method and reference lookups keep the member-only reply. Map summaryWithValues = summary; @@ -470,6 +684,8 @@ class ReaJadxBridge { "available_processors", Runtime.getRuntime().availableProcessors(), "java_version", System.getProperty("java.version"), "metadata_scope", "parsed_members")); + if (name.equals("rea_native_declarations")) + return json(nativeDeclarations(Path.of(string(args, "path")))); JadxSession current = session(); if (name.equals("get_app_info")) return json(manifest(current).summary()); if (name.equals("get_android_manifest")) @@ -581,7 +797,7 @@ class ReaJadxBridge { SessionHolder holder = new SessionHolder(defaults); ServerCapabilities capabilities = new ServerCapabilities( new ServerCapabilities.Tools(null), null, null, null, null, null, null, Map.of()); - Server server = new Server(new Implementation("rea-jadx-bridge", "7", null, null, null), + Server server = new Server(new Implementation("rea-jadx-bridge", "9", null, null, null), new ServerOptions(capabilities), "", ignored -> Unit.INSTANCE); SessionToolsKt.registerSessionTools(server, holder); ClassToolsKt.registerClassTools(server, holder); @@ -601,6 +817,11 @@ class ReaJadxBridge { new ToolSchema(null, new kotlinx.serialization.json.JsonObject(Map.of()), List.of(), null), "Observed worker JVM and metadata scope", null, null, null, null, null, null); server.addTool(diagnostics, (connection, request, continuation) -> bridge.handle("rea_jvm_status", request.getArguments())); + registerBridgeTool(server, bridge, "rea_native_declarations", + new ToolSchema(null, new kotlinx.serialization.json.JsonObject(Map.of("path", + new kotlinx.serialization.json.JsonObject(Map.of("type", + kotlinx.serialization.json.JsonElementKt.JsonPrimitive("string"))))), List.of("path"), null), + "Original ACC_NATIVE declarations from the admitted APK's standard root DEX members, without loading or decompiling the APK."); for (String name : List.of("get_app_info", "get_android_manifest")) { String description = name.equals("get_app_info") ? "Namespace-aware summary of the exact root AndroidManifest.xml resource." diff --git a/docs/android-analysis.md b/docs/android-analysis.md index 05c7e67fb1..50b2c57bba 100644 --- a/docs/android-analysis.md +++ b/docs/android-analysis.md @@ -286,6 +286,162 @@ instructions into field declarations, leaving an empty or incomplete method body. The selected method's disassembly preserves those instructions and retains the same source byte limit and explicit truncation reporting. +## Apply an R8/ProGuard mapping + +Release builds shrunk by R8 or ProGuard rename classes and members. Select the +build's `mapping.txt` with `mapping_path` on `inspect_android_class` or +`inspect_android_method`, or `--mapping-path` on the matching CLI command: + +```sh +rea inspect-android-class /path/Example.apk a.b --mapping-path /path/mapping.txt \ + --detail summary --evidence_output /tmp/class-evidence.json +``` + +For agent workflows, select `detail: "summary"` on class and method inspection. +It preserves the complete normalized member inventory or selected method body, +including mapping annotations, while retaining duplicate raw provider calls in +the complete parent Evidence. The reply links that parent's identity and digest; +export it with `export_evidence_bundle` or read its summary again through +`inspect_analysis_view`. CLI summaries require `--evidence_output` and return +the portable bundle path. Omitted or `complete` detail preserves complete inline +Evidence. Search and reference operations retain their existing contracts. +Symbol summary views admit at most **1 MiB**, including view context. An admitted +method's source can already consume that amount; a larger combined summary +fails explicitly instead of silently truncating facts. MCP refusal includes +the retained parent ID. Select complete detail, or inspect one method rather +than a whole class, when the requested summary does not fit. + +The mapping path must be absolute. Selectors still take the observed names, such as +`a.b`, and observed rows are unchanged. The result adds one `mapping` block with +the file's path, SHA-256 and size, the header values the file reports +(`compiler`, `compiler_version`, `min_api`, `map_version`, `pg_map_id`, +`pg_map_hash`), valid record counts and up to 16 malformed line samples. Its +`symbols` list has one entry per observed class, inner class, method and field; +`inspect_android_method` lists the class and the selected method. `coverage` +counts each resolution status. With summary delivery, these unchanged facts are +under the view's `summary` field; the view separately reports source coverage. + +Lookups use the bridge's raw DEX names, not JADX display aliases such as a +renamed reserved word. Each symbol resolves as: + +- `mapped`: exactly one record matches. A class needs one record for its raw + name (`verified_by: "class"`). A method must also match its DEX prototype + (`"descriptor"`) and a field its DEX type (`"type"`). R8 residual signature + metadata is used when present; otherwise original types are translated + through the file's class records. +- `ambiguous`: `multiple-records`, `descriptor-mismatch`, `type-mismatch`, + `ambiguous-class` or `residual-signature-conflict`, with `candidate_count` and + up to 8 candidates. Conflicting residual metadata never selects a winner. A name match + whose prototype or type does not verify is never reported as mapped. +- `unmapped`: no valid record matched the raw identity. +- `unknown` with reason `projection-budget`: this claim did not fit the combined + reply budget. The observed raw symbol remains present; `coverage.unknown` + counts these omissions. Inspect that specific class or method separately, + or consult the selected local mapping file for complete source records. + +A line continues an inline frame stack when it repeats the previous line's +minified range and obfuscated name and gives a single call-site line, such as +`:7`. Only the outermost original of a stack becomes a candidate. Original +line numbers and source files are not projected. Malformed records are counted +and skipped, so an `unmapped` symbol might be described by one of them. A file +that is missing, not a regular file, not UTF-8, larger than the byte limit or +without any class record, such as `usage.txt` or `seeds.txt`, is refused before +JADX is used. Requests read their mappings one at a time, in the same queue as +the JADX work and under the same operation deadline. A mapping failure therefore never starts or retires the JADX +session, and a different mapping reuses the loaded APK. + +## Link native declarations to JNI candidates + +When advertised, `inspect_android_jni_bindings` links original `ACC_NATIVE` +declarations from standard root `classes*.dex` members to bundled ELF libraries. +The supplied JAR's DEX reader preserves duplicate declarations before decompiler +deduplication. This operation does not load the APK into the decompiler. +MCP defaults to retained summary delivery when `detail` is omitted; select +`complete` explicitly to receive the full report inline. + +```json +{ + "path": "/absolute/Example.apk", + "class_name": "org.conscrypt.NativeCrypto", + "method_names": ["EVP_PKEY_new_RSA"], + "abis": ["arm64-v8a"], + "detail": "summary" +} +``` + +Class/method names and optional `descriptors` select raw DEX identities. +`library_paths` selects exact logical APK paths such as +`lib/arm64-v8a/libconscrypt_jni.so`; each library's `source_path` preserves its +original ZIP spelling. Omitted filters include all scoped facts; `[]` matches +none. Class selection never narrows the global inventory used for table-class +attribution. + +Independent `declarations`, `libraries`, `candidates` and `bindings` collections +have stable IDs and source ordinals. Candidates retain APK/library digests, +ABI, function addresses and file offsets. Table candidates also retain section, +table and entry identity plus all three name/signature/function pointer slots +and their relocation sources. JNI exports follow the +[UTF-16 escaping and short-before-long rules](https://docs.oracle.com/en/java/javase/21/docs/specs/jni/design.html#resolving-native-method-names); +failed escaping does not acquire an invented export match. Tables require +NUL-terminated [Modified UTF-8 strings](https://docs.oracle.com/en/java/javase/21/docs/specs/jni/types.html#modified-utf-8-strings), +valid descriptors and executable load mappings. REL, RELA and RELR retain +separate provenance; unsupported packed relocations and unresolved pointer +spans stay explicit unknowns. + +A static `JNINativeMethod` entry names no class. Attribute it uniquely only +when exactly one declaration in the complete recorded native inventory has +that `(name, descriptor)` pair. Multiple classes remain ambiguous after a +class filter; a partial inventory cannot establish unique attribution. + +Each selected declaration has a row per selected/observed ABI. `matched` means +candidate presence was observed; `ambiguous` means multiple observed targets +or class associations remain. Binding `coverage` is separate: a matched +partial row does not establish complete uniqueness, and an empty partial scan +is `unknown`, never `unmatched`. ELF/ABI label mismatches preserve facts without +asserting a binding. No result establishes library loading, runtime registration +or method invocation. + +Summary returns the first 64 selected binding rows, their declaration/candidate +closure and every selected library's identity, coverage and failure reason; +counts and page coverage describe the full selected binding set. Selected +declaration IDs have separate preview coverage, so native declarations remain +visible even when the APK has no bundled ABI libraries. Complete +Evidence stays retained. Read exact fields or further pages without reopening +files or rerunning analysis: + +```json +{ + "source": { "kind": "retained-evidence", "evidence_id": "ev_" }, + "view": { + "kind": "android-jni", + "collection": "bindings", + "offset": 64, + "limit": 64, + "fields": ["declaration_id", "abi", "status", "coverage", "candidate_ids"] + } +} +``` + +Collections also include `declarations`, `candidates` and `libraries`, with +exact filters and batch lookup by declaration/candidate/library IDs. `row_index` +is the original parent collection index; DEX and +ZIP source ordinals stay separate. Complete detail returns the full report. +CLI uses the same selection and delivery contracts. Its common one-shot +default remains complete; summary delivery requires an explicit Evidence path: + +```sh +rea inspect-android-jni-bindings /absolute/Example.apk \ + --query '{"class_name":"org.conscrypt.NativeCrypto","method_names":["EVP_PKEY_new_RSA"],"abis":["arm64-v8a"]}' \ + --detail summary --evidence_output /absolute/fresh-jni-evidence.json +``` + +Optional `--view` accepts the same JSON page and requires summary delivery. +Evidence bundles never overwrite files. Complete declarations and one library +selection are cached within the immutable APK session. Changing ABI/library +selection replaces the scan; class/method selection reuses it. Fresh analysis +still validates current caller APK bytes. Idle/close releases the caches; +retained Evidence remains historical and independently readable. + ## Interpret the result - Package inspection retains decoded manifest XML, summary declarations, @@ -322,6 +478,11 @@ the same source byte limit and explicit truncation reporting. `dex_descriptor`, for example `(I)V`. Display names can be JADX aliases; the descriptor alone is not a complete raw DEX method ID. Overload indices are tied to this artifact and engine, not stable identities across builds. +- A `mapping` block appears only when the caller selected `mapping_path`. Its + names are claims from that file, not observations of the APK. REA does not + check that the mapping belongs to this build; `pg_map_id` is reported, not + compared. Evidence keeps the selected path in its parameters and the file's + SHA-256 in the result. - Method inspection reports Java or smali, fallback markers and complete/partial returned text. Decompiled source is a derived representation. A complete text result does not establish complete semantics or a byte-identical reconstruction. @@ -411,6 +572,19 @@ target/configuration changes, failure, timeout, cancellation, MCP disconnect or server shutdown. One-shot CLI commands always join cleanup before returning. REA never writes to the original APK or launches target code. +JNI scans reuse the analyzer process without loading the APK into the +decompiler. They admit at most 64 MiB per DEX member and 256 MiB of DEX bytes, +with a 4 MiB native-declaration JSON allowance before MCP string escaping. +Native libraries are processed sequentially: one 64 MiB buffer, 256 MiB total +selected read work, and a 16 MiB parsed-library-facts allowance. ZIP inventory +and library counts also have explicit resource bounds. Unexamined occurrences +remain unknown. A complete relationship report has a separate 16 MiB serialized +allowance; summaries/pages allow 1 MiB including their provenance envelope. +These are resource admissions, not claims about maximum valid Android formats. +Select fewer ABI/library occurrences or smaller retained pages when needed. +Completed parsed library facts survive failed reader finalization in typed +partial observations; the exact reader owner remains available for cleanup retry. + On Windows, stdin writes preserve stream backpressure and run outside the Node event loop. Cancellation terminates the retained job, including descendants, before workspace cleanup. On Windows, a detached REA helper owns the private @@ -496,6 +670,27 @@ complete, case-sensitive search contract. A protocol frame above **8 MiB**, or c **32 MiB per operation**, fails with a diagnostic instead of returning an incomplete inventory as complete. These are memory-safety boundaries, not undocumented result caps. +A selected R8/ProGuard mapping is re-read and SHA-256 checked on every call, up +to **64 MiB**. The serialized provider keeps one successful parsed index, keyed +by byte length and digest with fixed parser options. Identical bytes reuse that +index; changed bytes are reparsed, missing files still fail, and each response +preserves the currently selected path. The index is released on provider idle +retirement or close. Omitting `mapping_path` never applies the cached mapping. +During replacement, the old index can coexist with the new parse until it +succeeds; these transient allocations count toward process memory. + +Before retaining records, the parser admits an estimated **128 MiB** index +representation and **8 MiB** of expanded mapped claims per residual class, +including shared header facts. The index allowance accounts for strings and +containers; it is not a measured V8 heap cap. Parameter and metadata expansion +is admitted before splitting or JSON decoding. These fixed resource bounds +have no runtime override; refusal reports `resource_constraint`, the source +line and mapping SHA-256. Ambiguous lookups count all candidates while keeping +only the first eight in stable file order. A separate **8 MiB** combined claim +budget applies to the actual query set, including outer and inner classes, +before cloning the report. Claims that do not fit become explicit `unknown` +entries; other admitted claims and all observed identities remain available. + ## Real verification Download the explicit public fixtures once; this installs no tools: diff --git a/docs/architecture.mermaid b/docs/architecture.mermaid index 91603c944e..4f36c28aac 100644 --- a/docs/architecture.mermaid +++ b/docs/architecture.mermaid @@ -75,7 +75,7 @@ graph TD end subgraph "Domain Layer" - DOMAIN["src/domain/
Pure side-effect-free modules
format declarations, Evidence, comparisons, application graphs"] + DOMAIN["src/domain/
Pure side-effect-free modules
format declarations, provider selection, Evidence, comparisons, application graphs"] end subgraph "Configuration" diff --git a/docs/client-configuration.md b/docs/client-configuration.md index e62d11ae9a..420b76273b 100644 --- a/docs/client-configuration.md +++ b/docs/client-configuration.md @@ -497,17 +497,51 @@ comments and unrelated settings. It resolves that file from `HERMES_HOME`, else from the platform default Hermes itself uses โ€” `%LOCALAPPDATA%\hermes` on Windows, `~/.hermes` elsewhere โ€” including any `HERMES_DATA_DIR_SUFFIX`. Hermes connects an entry unless `enabled` is false, so setup states `enabled: true`. +Aliases whose anchor is defined in the `rea` entry retain their original resolved +values when setup refreshes or uninstall removes that entry. Setup does not +redirect another server's alias to REA's new launcher or policy. +This also covers an anchor on the removed registration key. References to +definitions outside the entry keep sharing the original value, including when +another definition later reuses the same anchor name. Hermes personal skills install under the active Hermes home's `skills` directory. -Setup, doctor and uninstall follow the root's `active_profile` selection, as -plain Hermes CLI commands do. An explicit `HERMES_HOME` pointing to -`profiles/` selects that named profile directly. An invalid, missing or -deleted sticky profile is reported instead of writing into the default home; -it also remains an unresolved skill selection, so setup cannot report a -successful empty installation. Overrides nested beneath the native Hermes home -use that native home's sticky selection and profile root together, matching -[Hermes's root rules](https://github.com/NousResearch/hermes-agent/blob/748c79a1c6873124d84071cdabb4062a75913e1f/hermes_constants.py#L83). -Repair the profile or run `hermes profile use default` before retrying. +Setup, doctor and uninstall share REA's sticky-profile resolver. +A custom `HERMES_HOME` outside the platform default home +reads its own `active_profile`. An override physically inside the default home +uses that default home's sticky selection and profile root together, including +when the final override directory does not yet exist. + +For example, with `HERMES_HOME=~/.hermes/sub` and `~/.hermes/active_profile` set +to `coder`, setup selects `~/.hermes/profiles/coder/config.yaml` and that +profile's skills directory. It does not read `~/.hermes/sub/active_profile`. +Without an outer named selection, this override uses `~/.hermes/sub/config.yaml`. +Use a home outside the platform default tree for an independent sticky selection. + +This describes REA's current routing, not full Hermes CLI equivalence. +At Hermes commit `748c79a1`, the +[sticky lookup](https://github.com/NousResearch/hermes-agent/blob/748c79a1c6873124d84071cdabb4062a75913e1f/hermes_cli/main.py#L612-L632) +also reads the outer selection, but +[`resolve_profile_env`](https://github.com/NousResearch/hermes-agent/blob/748c79a1c6873124d84071cdabb4062a75913e1f/hermes_cli/profiles.py#L2431-L2461) +resolves it beneath the configured `HERMES_HOME`. For nested overrides, confirm +the profile Hermes actually uses and point `HERMES_HOME` directly at that +`profiles/` directory before setup. Compatibility is tracked in +[#3939](https://github.com/morluto/rea/issues/3939). + +REA resolves existing ancestor directories before checking physical containment, +including symlinks and junctions, even when the override directory does not exist. +An override beneath a symlinked default home therefore uses the default home's +sticky selection. If `~/.hermes/link` points outside the default home, +`HERMES_HOME=~/.hermes/link/new` instead uses that override root, whether or not +`new` exists. Previewed destinations retain the configured path spelling. +An unreadable path or dangling alias leaves the home unresolved; repair that path +before configuring Hermes. Inspect setup's previewed destinations before applying +changes. + +An explicit `HERMES_HOME` pointing to `profiles/` selects that named +profile directly, bypassing sticky selection. An invalid, missing or deleted +sticky profile is reported instead of writing into the default home; repair the +profile or run `hermes profile use default` before retrying. It also remains an +unresolved skill selection, so setup cannot report a successful empty installation. REA follows `HERMES_HOME` whitespace trimming, environment-variable expansion, and home expansion before resolving that profile. Setup previews the resolved configuration and skill destinations; doctor and uninstall use those same paths. @@ -524,10 +558,12 @@ installs its skill copy there. ## Factory Droid For [Factory Droid](https://docs.factory.com/harness/mcp), setup writes -`mcpServers.rea` into the user-level `~/.factory/mcp.json`. Entries carry -`command`, `args`, and `env`. Droid discovers personal skills from -`~/.factory/skills` ([skills](https://docs.factory.com/harness/skills)), so -setup installs its skill copy there. +`mcpServers.rea` into the user-level `~/.factory/mcp.json` (the +`FACTORY_HOME_OVERRIDE` override replaces the home that contains `.factory`). +Entries carry `command`, `args`, and `env`. Droid discovers personal skills +from `~/.factory/skills` ([skills](https://docs.factory.com/harness/skills), +following `FACTORY_HOME_OVERRIDE` when set), so setup installs its skill copy +there. ## Trae @@ -703,10 +739,6 @@ can override an inherited disable. Lower files and other server entries remain unchanged; a legacy server named `servers` that conflicts with the native table requires manual repair before setup can write. -When Hermes aliases refer to an anchored REA entry, refreshing or removing REA -retains the aliases' original resolved values. Setup does not redirect another -server's alias to REA's new launcher or policy. - With no client selected, the interactive skill choice targets the shared `~/.agents/skills` copy. Selecting a client targets its personal destination when supported. Use `rea setup --skill-client shared --skill` for the shared diff --git a/docs/harmony-analysis.md b/docs/harmony-analysis.md index 468cdd347f..a671a2ef7d 100644 --- a/docs/harmony-analysis.md +++ b/docs/harmony-analysis.md @@ -36,7 +36,7 @@ The MCP tool `project_harmony_application_graph` takes the same - exact component paths, artifact IDs, and hashes (manifests, Ark bytecode, resources, native libraries, JavaScript, signing) -- a packaging-model hint: Stage is claimed only from a `module.json` entry +- a packaging-model hint: Stage is claimed only from an exactly cased `module.json` entry outside a classified resource path, FA only from `config.json` outside a classified resource path, otherwise `unknown` - FA resources under `assets//resources/` as well as Stage `resources/` @@ -46,6 +46,9 @@ The MCP tool `project_harmony_application_graph` takes the same - path-based N-API bridge hypotheses between bytecode and `libs/` native libraries +An unavailable manifest can still supply a path-based model hint; its content +identity remains unknown. Manifest names follow case-sensitive ZIP member names. + File and slice occurrences supply component and child-package paths; directory trees and symlinks retain their identities in the source inventory without being classified as code files. Ark and JavaScript runtime hints summarize the diff --git a/docs/ida-provider.md b/docs/ida-provider.md index 491a0d67e5..9f2a2f262a 100644 --- a/docs/ida-provider.md +++ b/docs/ida-provider.md @@ -240,7 +240,7 @@ The verifier requires the resolved procedure in both inventory and procedure sea The initial real workflows use stdio registrations for the legacy Windows GUI profile and a Windows x64 headless supervisor with IDA 9.3. The headless workflow has also passed on macOS arm64 with IDA Professional 9.1 (build 9.1.250226) against the same upstream commit `c133c3853faa111a9b00ee615c013b720d0c4acd`, using a source-built arm64 Mach-O fixture; Mach-O C symbols carry a leading underscore, so the procedure name is `_rea_fixture_add`. Streamable HTTP is tested against a loopback MCP fixture with the pinned client SDK; a real IDA HTTP-supervisor workflow remains unverified. Linux headless engine operation, other IDA releases, architectures, and modern attached GUI tools require their corresponding real workflows before support is claimed. -Native Windows verification uses IDA Pro 9.3 with the public two-function fixture and Windows `whoami.exe`, using upstream `c9d15d98e8a143fc74f6e14037c48f63889b6d6c` with a loopback-listener change. It covers production CLI/MCP parity, distinct-function switching, identity and connection cleanup. See the [correctness and performance measurements](https://github.com/morluto/rea/blob/main/experiments/analysis-efficiency/ida-native-windows.md). This follow-up did not run Windows IDA Free or native macOS. +Native Windows verification uses IDA Pro 9.3 with the public two-function fixture and Windows `whoami.exe`, using upstream `c9d15d98e8a143fc74f6e14037c48f63889b6d6c` with a loopback-listener change. It covers production CLI/MCP parity, distinct-function switching, identity and connection cleanup. See the [correctness and performance measurements](https://github.com/morluto/rea/blob/a2e2c29b59e8775b0e6aedb09a9eb16adf32646b/experiments/analysis-efficiency/ida-native-windows.md). This follow-up did not run Windows IDA Free or native macOS. Headless readiness distinguishes an explicit `auto_analysis_ready: false` from unknown readiness (`null`). The former returns a retryable capability refusal diff --git a/docs/installation.md b/docs/installation.md index af9a96bff3..2bd90427db 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -3,13 +3,14 @@ Run REA, connect your selected agents, and check the tools needed for your task. Setup previews configuration changes and asks for approval before applying them. -| Task | Section | -| --------------------------------- | --------------------------------------------------------------------------------------------------- | -| Connect an agent | [Start setup](#start-setup), then [review changes](#review-setup-changes) | -| Diagnose one task | [Scoped readiness checks](#check-readiness-for-your-task) | -| Configure an analysis engine | [Hopper](#hopper), [Ghidra](#ghidra), the [IDA guide](ida-provider.md), or [Kuna](kuna-provider.md) | -| Update or remove REA | [Maintenance](#diagnose-update-and-remove) | -| Resolve a client-specific problem | [Client configuration](client-configuration.md) | +| Task | Section | +| ---------------------------------- | --------------------------------------------------------------------------------------------------- | +| 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) | +| Diagnose one task | [Scoped readiness checks](#check-readiness-for-your-task) | +| Configure an analysis engine | [Hopper](#hopper), [Ghidra](#ghidra), the [IDA guide](ida-provider.md), or [Kuna](kuna-provider.md) | +| Update or remove REA | [Maintenance](#diagnose-update-and-remove) | +| Resolve a client-specific problem | [Client configuration](client-configuration.md) | ## Start setup @@ -444,6 +445,9 @@ and other MCP servers. Purging removes REA's legacy cache and state under archives under `${XDG_CACHE_HOME:-~/.cache}/rea/hopper-releases`. Other cache namespaces remain intact. A caller-selected `REA_KUNA_CACHE_DIR` is retained and reported because REA cannot establish ownership of its entire contents. +Lexically equivalent spellings of that default directory, including a trailing +separator, a `.` segment, or a repeated separator, share its purge result. +The comparison preserves POSIX `..` traversal and literal backslashes. A client configuration that is malformed, unreadable, or at an unsafe path stops the operation before anything is removed, and a client that fails while being updated stops the remaining removals. Uninstall reports each @@ -1433,6 +1437,21 @@ current setting. For Windows PE resource analysis, the exact name is `WindowsResourceReference`. Disabling an analyzer skips the facts it would have produced. +Ghidra's Objective-C Message Analyzer can log +`Required Objective-C data type not found in data type manager` / +`Try adding libobjc.dylib` when a Mach-O links Objective-C runtime symbols but +defines no class metadata (thin Cocoa glue in a C++ binary is a common case). +That text is non-fatal Ghidra analyzer output: auto-analysis continues, and the +analyzer simply skips `objc_msgSend` call-target recovery. REA's headless import +does not accept a "add this library" option, and on modern macOS +`/usr/lib/libobjc.A.dylib` exists only in the dyld shared cache, so there is no +on-disk library to add. Treat the line as a coverage limitation, not an REA +failure; check the session's `failure_kind` (and related provider errors) for +any real abort. To silence that analyzer, set +`REA_GHIDRA_DISABLED_ANALYZERS="Objective-C Message Analyzer"`. For large +executables that miss the startup deadline instead, raise +`REA_GHIDRA_STARTUP_TIMEOUT_MS` and the [Ghidra heap](#ghidra-heap-and-cpu-controls). + ### Ghidra heap and CPU controls Set resource controls in the environment that launches the CLI or MCP server, @@ -1534,6 +1553,87 @@ read-only operations, digest identity, and runtime cleanup. The separate ordinary user. It requires the built Windows native bundle and an existing Ghidra/JDK installation; neither is inferred from startup alone. +## Agent plugins and marketplaces + +REA's npm package is the shared Claude Code and Codex plugin artifact. It +contains `.claude-plugin/plugin.json`, `.codex-plugin/plugin.json`, and the +canonical generated `skills/` tree. Both manifests select `./skills` and run a plain Node bootstrap pinned to +that exact package version. The client must have a supported standalone `node` +on its PATH. Claude expands its documented `CLAUDE_PLUGIN_ROOT` in the script +argument; Codex resolves `cwd: "."` from the installed plugin root before +launching the relative script. The bootstrap verifies the package version and runs its bundled runtime in +the same process, preserving stdio and REA's provider/worker cleanup. It does +not start another package runner or download a different runtime. The existing release skill +generator also pins CLI recovery commands to the same version. + +The repository's single-plugin marketplaces are declared in +`.claude-plugin/marketplace.json` and `.agents/plugins/marketplace.json`. +Both select an exact `rea-agents` npm version instead of mutable source-checkout +contents. Release Please updates their selectors alongside the plugin manifests. +No plugin-only publication or generated skill files committed to Git are needed. +The qualified release archive contains a runtime-only manifest and +`npm-shrinkwrap.json` plus bundled runtime dependencies, including PTY packages +for each supported OS and CPU; development dependencies and development-only overrides +stay in the source manifest and lockfile. Both clients receive this same archive. + +This distribution becomes installable after the first qualified npm release +containing these plugin manifests. Earlier published packages are not changed +by this source proposal. For local source development, run `npm ci && npm run build:cached` to generate +the runtime and packaged skill before loading the repository as a plugin. +A source plugin uses the locally built runtime and generated skill; rebuild after +source changes. Missing builds and mismatched version pins fail with an actionable +error. The authored `.agents/skills/` tree is not the plugin's shipped skill layout. +Windows source workflows that need native controls still require the +[Windows source-checkout build](https://github.com/morluto/rea/blob/main/native/windows/README.md#build). + +In Claude Code: + +```text +/plugin marketplace add morluto/rea +/plugin install rea@rea +``` + +In Codex CLI, add the marketplace and install REA: + +```bash +codex plugin marketplace add morluto/rea +codex plugin add rea@rea +``` + +Each release updates both manifest versions and their pinned server version +together, which is when installed copies refresh the bundled skill and move to +the new server. A plugin does not run `rea setup`, so provider +configuration still follows the sections above. Use the plugin or a +`rea setup` registration for a client, not both, to avoid two `rea` servers. + +`rea doctor` does not see plugin-owned state. Its client and skill checks read +only the registrations and skill locations that `rea setup` manages, so for a +plugin-only install `rea doctor --client ` and `rea doctor --skill` report +`missing` and recommend `rea setup`. Do not follow that remediation. Check the +plugin with the client instead (`claude plugin list` and `/mcp` in Claude +Code, `codex plugin list` in Codex). + +For analysis engines, ask the connected server: have the agent call +`binary_session` and read `result.tool_availability`, which reports what the +server the plugin started can use, with reasons and remediation. See +[MCP contracts](mcp-contracts.md). + +A plugin does not put `rea` on your `PATH`. To check an engine from a +terminal, use the package runner at the version the plugin pins: + + + +```bash +npx -y rea-agents@6.8.0 doctor --provider ghidra --json +``` + + + +If your installed plugin is older, use the version in its manifest instead. +That report describes the terminal's environment, not the plugin server's. +The server inherits the client's environment, so a setting such as +`GHIDRA_INSTALL_DIR` that exists only in your terminal does not reach it. + ## MCP Registry REA is published in the official MCP Registry as `io.github.morluto/rea`. Registry diff --git a/docs/mcp-contracts.md b/docs/mcp-contracts.md index 4d3a7545b4..ca46e63f16 100644 --- a/docs/mcp-contracts.md +++ b/docs/mcp-contracts.md @@ -1248,11 +1248,22 @@ failures for such entries name this cause and the operation to rerun with Advertised input and output schemas contain no reachable recursive references. Input schemas inline repeated definitions before applying the selected presentation profile. Both `full` and `compact` start from this self-contained -projection; output schemas can share schema-local definitions. Full inputs -retain nested fields, descriptions and valid literal examples. The compatibility +projection; output schemas can share schema-local definitions. Analyst-authored +full inputs retain nested fields, descriptions and valid literal examples. The compatibility projections below can relax advertised constraints; canonical runtime validation still enforces the complete input contract. +`compare_web_captures` declares its complete producer observations as object +operands instead of repeating their full output schemas in the input catalog. +Pass the original `inspect_web_page` normalized result in `before.inspection` +and `after.inspection`, optional complete `discover_webmcp_tools` results in +`webmcp`, or complete `capture_browser_scenario` results in the scenario fields. +Do not construct partial observations from the abbreviated declaration: the +server still validates every canonical field before comparison. Input groups +and analyst-authored normalization rules remain explicit. This presentation +changes no capture bytes, identity, completeness, or comparison semantics and +does not reduce `inspect_analysis_view` selectors or other tools' declarations. + When a host forwards input schemas to the model, their examples consume context. REA's advertised examples therefore never copy complete producer Evidence. An embedded Evidence record is shown as its exact `{"kind":"retained-evidence","evidence_id":"ev_..."}` diff --git a/docs/releases/6.4.0.contributions.json b/docs/releases/6.4.0.contributions.json deleted file mode 100644 index e5a5898a5a..0000000000 --- a/docs/releases/6.4.0.contributions.json +++ /dev/null @@ -1,9434 +0,0 @@ -{ - "schemaVersion": 1, - "repository": "morluto/rea", - "version": "6.4.0", - "base": "74cf9e1401fcd89482fe39c27cc898f5858e9b72", - "target": "ee46323b493994902b04824a7dc8aae2a8117903", - "commits": [ - { - "sha": "08ec2bf82fa88f5e8caa2b7da9093636731dc55c", - "subject": "chore(main): release rea-agents 6.3.0 (#1341)", - "body": "chore(main): release rea-agents 6.3.0 (#1341)\n\nCo-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>", - "parents": ["001851fde6f972e6ebd01fddccdff4c645a85f63"], - "authors": [ - { - "name": "github-actions[bot]", - "email": "41898282+github-actions[bot]@users.noreply.github.com", - "user": { - "login": "github-actions[bot]", - "__typename": "User" - } - } - ], - "pullRequests": [1341] - }, - { - "sha": "7aa4d768eb15317a63a476431ed75bafec086033", - "subject": "chore(release): sync corrected 6.3 checkpoint", - "body": "chore(release): sync corrected 6.3 checkpoint\n", - "parents": [ - "08ec2bf82fa88f5e8caa2b7da9093636731dc55c", - "74cf9e1401fcd89482fe39c27cc898f5858e9b72" - ], - "authors": [ - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - } - ], - "pullRequests": [] - }, - { - "sha": "5fc4d792caeb3cd81c2021e45a158c5127906c56", - "subject": "fix(javascript): handle oversized inline source maps (#1386)", - "body": "fix(javascript): handle oversized inline source maps (#1386)\n\n* fix(javascript): handle oversized inline source maps\n\n* fix(javascript): avoid source map directive regex overflow", - "parents": ["7aa4d768eb15317a63a476431ed75bafec086033"], - "authors": [ - { - "name": "Minghang Chamling", - "email": "133689405+cold-atom@users.noreply.github.com", - "user": { - "login": "cold-atom", - "__typename": "User" - } - } - ], - "pullRequests": [1386] - }, - { - "sha": "498cec042a5f05557ae9c2ef9663d41dd03901c3", - "subject": "fix(cli): stop advertising multi-letter single-dash option aliases (#1395)", - "body": "fix(cli): stop advertising multi-letter single-dash option aliases (#1395)\n\nIncur's `alias` map registers one-letter short flags and already accepts\nkebab-case spellings of camelCase options. Twenty options registered their\nkebab-case long name as an \"alias\", so help and completions advertised\nflags such as `-case-sensitive` and `-relative-path` that the parser reads\nas stacked short flags and rejects with \"Unknown flag: -c\".\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["5fc4d792caeb3cd81c2021e45a158c5127906c56"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1395] - }, - { - "sha": "2b6e9ec03f88abb0799a4d154e48544ff4685a41", - "subject": "fix(browser): classify selected web trace file failures by cause (#1396)", - "body": "fix(browser): classify selected web trace file failures by cause (#1396)\n\ntrace_web_module_imports and trace_web_source_location reported a missing\nor non-file manifest, source map or import map as artifact_operation_failed\n(\"Artifact could not be read or written\" / \"unsafe or conflicting internal\npath\"). These are caller selections: report ENOENT/ENOTDIR and non-regular\nfiles as invalid input on the selected field, and EACCES/EPERM as a host\naccess denial. A missing manifest-derived source file stays an artifact fault.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["498cec042a5f05557ae9c2ef9663d41dd03901c3"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1396] - }, - { - "sha": "6875d4a64c0d77c4f90ebbec36705f191eb7cdc6", - "subject": "fix(cli): accept JSON files for web capture and screenshot comparisons (#1397)", - "body": "fix(cli): accept JSON files for web capture and screenshot comparisons (#1397)\n\ncompare-web-captures and compare-web-screenshots parsed their arguments as\ninline JSON only, unlike every other JSON-input command. Screenshot\nartifacts and scenario captures embed base64 PNG bytes, so a typical\nviewport screenshot exceeds the command-line length limit (128 KiB per\nargument on Linux, 1 MiB total on macOS) and could not be compared from\nthe CLI at all, while MCP accepts it. A file path was reported as\nmalformed JSON, and screenshot schema failures returned no issues.\n\nEach argument now accepts inline JSON or a JSON file path through\nparseCliJsonInput; file failures keep its path diagnostics, malformed\ninline JSON keeps the field issue, and screenshot validation reports\nprojected schema issues. The tests share one CLI JSON process fixture.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["2b6e9ec03f88abb0799a4d154e48544ff4685a41"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1397] - }, - { - "sha": "499e2f54efc65aff427978613284c3e429398d44", - "subject": "perf(evidence): stop copying normalized results into raw_result (#1402)", - "body": "perf(evidence): stop copying normalized results into raw_result (#1402)\n\ncreateAnalysisExecution defaulted an omitted rawResult to a second\ncomplete copy of the result. Every caller that had no distinct provider\nrepresentation therefore doubled its Evidence: decode_interface_builder,\ninspect_keyed_archive, inspect_asset_catalog, trace_dylib_resolution,\ninspect_native_dispatch_metadata, observe_native_calls,\nobserve_native_ui/capture_native_ui_scenario (including screenshots), and\nsmall Ghidra/IDA lifecycle records. Sibling operations of the same\nproviders already recorded null.\n\nAn omitted rawResult now records null. Normalized results are unchanged.\nMCP responses repeat Evidence in text and structured content, so each\nresponse and its share of the 10 MiB transport budget shrink by the same\nhalf; e.g. trace_dylib_resolution on a real app bundle drops from\n3,217,119 to 1,612,524 bytes per representation.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["6875d4a64c0d77c4f90ebbec36705f191eb7cdc6"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1402] - }, - { - "sha": "7623e21ff02cf4eb00ccb4fa357936e4ed01425e", - "subject": "perf(native): record pwntools diagnostics once in their Evidence (#1404)", - "body": "perf(native): record pwntools diagnostics once in their Evidence (#1404)\n\ninspect_binary_layout and inspect_recorded_crash passed the decoded report\nas both result and rawResult, so every Evidence record carried the whole\nreport twice (and an MCP response four times, counting its text copy).\nThe decoded report is the only representation, so raw_result is now null,\nas for other single-representation operations.\n\nThe real pwntools verifiers asserted the duplicate; they now assert null.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["499e2f54efc65aff427978613284c3e429398d44"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1404] - }, - { - "sha": "1f0f728c63a4d9f32fc183c6a41627eedb8d1fe2", - "subject": "perf(hopper): stop repeating Hopper replies as raw_result (#1405)", - "body": "perf(hopper): stop repeating Hopper replies as raw_result (#1405)\n\nHopperProvider passed the bridge reply as rawResult and, for every\noperation except address_to_file_offset, the same object as the result.\nEvery Hopper Evidence record (decompilation, procedure and string\nlistings, xrefs, ...) therefore carried its complete result twice, and\nan MCP response four times counting its text copy.\n\nraw_result is now null unless REA transformed the reply, which only the\nfile-offset mapping does; that case keeps Hopper's original reply.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["7623e21ff02cf4eb00ccb4fa357936e4ed01425e"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1405] - }, - { - "sha": "8550913cda311e5340cf012b9c4afd622e36e35b", - "subject": "fix(javascript)!: stop copying literals into semantic metadata (#1407)", - "body": "fix(javascript)!: stop copying literals into semantic metadata (#1407)\n\nCommit literal values with canonical JSON SHA-256 in semantic role keys\nand use a type label for strings. Preserve complete values, provenance and\nliteral queries while avoiding two payload copies in each string node.\n\nVerify real compiled CLI/default stdio MCP, typed union seeds, empty\nstrings and trace continuation with a large source-owned fixture.\n\nRefs #723\n\nBREAKING CHANGE: Newly produced semantic literal node IDs use\nvalue-sha256 role keys, and string labels read \"string literal\". Read exact\nvalues from properties.value and obtain node IDs from the selected parent\ngraph. Previously stored Evidence and its original IDs remain valid.", - "parents": ["1f0f728c63a4d9f32fc183c6a41627eedb8d1fe2"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1407] - }, - { - "sha": "de8fc6719596305b1d76204e6b052cf46d7e7fc3", - "subject": "fix(javascript): retain shorter literal metadata encodings (#1408)", - "body": "fix(javascript): retain shorter literal metadata encodings (#1408)\n\nChoose the shorter complete JSON or digest key and string display label.\nShort values keep their existing identities and labels, while large values\nretain the payload-copy reduction without an arbitrary truncation limit.", - "parents": ["8550913cda311e5340cf012b9c4afd622e36e35b"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1408] - }, - { - "sha": "ca3131b36ccf025f64b9e43ecae2698d37747de7", - "subject": "perf(cli): write compact JSON when output is not a terminal (#1413)", - "body": "perf(cli): write compact JSON when output is not a terminal (#1413)\n\n`--json` / `--format json` always indented its streamed result. Agents and\nscripts read REA through pipes and redirects, where indentation carries no\ninformation: on real application results it added 16-45% model tokens\n(o200k proxy) and 25-73% bytes. The skill's CLI fallback uses `--json`.\n\nIndent only when stdout is a TTY, as `gh --json` does; piped or redirected\nJSON is compact. The JSON value, `jsonl`, `--filter-output`,\n`--full-output` and the token-window paths are unchanged. `jq .` restores\nindentation for files.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["de8fc6719596305b1d76204e6b052cf46d7e7fc3"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1413] - }, - { - "sha": "4d8ef3f35022f286e5a6b2ee250cfb336e14a4ad", - "subject": "perf(javascript): aggregate semantic family coverage once (#1410)", - "body": "perf(javascript): aggregate semantic family coverage once (#1410)\n\nReduce repeated semantic relation and unknown family scans while preserving exact complete Evidence and coverage.", - "parents": ["ca3131b36ccf025f64b9e43ecae2698d37747de7"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1410] - }, - { - "sha": "81cdafc132c7ba3bd6e12b1169f9e3687025d07b", - "subject": "docs: celebrate 50,000 GitHub stars ๐ŸŽ‰", - "body": "docs: celebrate 50,000 GitHub stars ๐ŸŽ‰", - "parents": ["4d8ef3f35022f286e5a6b2ee250cfb336e14a4ad"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1349] - }, - { - "sha": "98022a835275375ee0ffa88b7c8983ba6f080040", - "subject": "fix(javascript)!: avoid endpoint payload copies in graph metadata (#1423)", - "body": "fix(javascript)!: avoid endpoint payload copies in graph metadata (#1423)\n\nKeep exact endpoint observations and request properties while using compact display labels and collision-safe canonical value digests for long artifact-local endpoint keys. Verify real CLI/stdio MCP tracing and version comparison without truncating evidence.\n\nBREAKING CHANGE: New analyses use compact endpoint labels and digest-based IDs for long or reserved-prefix endpoint keys. Select IDs from the parent graph and read full values from endpoint properties. Previously stored graphs retain their original identities and remain valid workflow inputs.", - "parents": ["81cdafc132c7ba3bd6e12b1169f9e3687025d07b"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1423] - }, - { - "sha": "28595276faac6a01dd4930313a91fab717d29513", - "subject": "fix(javascript): bound member-mutation paths through reassignment loops", - "body": "fix(javascript): bound member-mutation paths through reassignment loops\n\nFixes #1401. Refs #1065. Preserve exact member facts and equal-depth write effects while bounding the observed reassignment-loop expansion.\n\nValidated with the JavaScript semantic/application suite, focused alias regressions, full static checks, real compiled CLI and SDK MCP Notion workflows, and all 20 checks on the final PR head.\n\nCo-Authored-By: Marnix Pluim <286664873+marnixpluim@users.noreply.github.com>\nCo-Authored-By: N0zoM1z0 <161784452+N0zoM1z0@users.noreply.github.com>\nCo-Authored-By: Claude ", - "parents": ["98022a835275375ee0ffa88b7c8983ba6f080040"], - "authors": [ - { - "name": "Marnix Pluim", - "email": "marnixjaap@gmail.com", - "user": { - "login": "marnixpluim", - "__typename": "User" - } - }, - { - "name": "Marnix Pluim", - "email": "286664873+marnixpluim@users.noreply.github.com", - "user": { - "login": "marnixpluim", - "__typename": "User" - } - }, - { - "name": "N0zoM1z0", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - }, - { - "name": "Claude", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1390] - }, - { - "sha": "4d95f2b2e7a6fdc1ba9dfcbd90578f6bbc5e5e1e", - "subject": "fix(validation): retain unmatched union correction details", - "body": "fix(validation): retain unmatched union correction details\n\nPreserve actionable field paths and schema-declared variants for unknown or missing discriminators.\n\nCloses #1421. Refs #1065.", - "parents": ["28595276faac6a01dd4930313a91fab717d29513"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1425] - }, - { - "sha": "a9ee2360fd11332b2cc50ef7130a89321b828d28", - "subject": "feat(native): inspect oversized retained function dossiers via bounded views", - "body": "feat(native): inspect oversized retained function dossiers via bounded views\n\nAdd caller-selected native dossier facets with preserved Evidence identity, provenance, unknowns and transport recovery.\n\nRefs #1247 and #1065.\n\nCo-authored-by: jhuang-tw <77732008+jhuang-tw@users.noreply.github.com>\nCo-authored-by: N0zoM1z0 <161784452+N0zoM1z0@users.noreply.github.com>", - "parents": ["4d95f2b2e7a6fdc1ba9dfcbd90578f6bbc5e5e1e"], - "authors": [ - { - "name": "jhuang-tw", - "email": "77732008+jhuang-tw@users.noreply.github.com", - "user": { - "login": "jhuang-tw", - "__typename": "User" - } - }, - { - "name": "N0zoM1z0", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1345] - }, - { - "sha": "f4a0c1ce95375c1661ca95b414829113a10298b8", - "subject": "fix(javascript)!: avoid event payload copies in graph metadata (#1427)", - "body": "fix(javascript)!: avoid event payload copies in graph metadata (#1427)\n\nShare the canonical string identity rule with endpoint projection, scope event keys to each emitter, and keep complete event/listener names in properties. Verify real CLI and stdio MCP with large names, registration/removal, distinct emitters, exact name seeds, reserved-prefix values, and unresolved dynamic names.\n\nBREAKING CHANGE: New analyses use digest-based IDs for long or reserved-prefix event names and shorter event/listener display labels. Select IDs from the parent graph and read exact names from event_name properties. Stored graphs and their original IDs remain accepted for semantic tracing.", - "parents": ["a9ee2360fd11332b2cc50ef7130a89321b828d28"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1427] - }, - { - "sha": "c29931ce81dc530d2623ec992714a70b1f3e50e4", - "subject": "fix(javascript): scan direct returns without recursive stack growth", - "body": "fix(javascript): scan direct returns without recursive stack growth\n\nUse the shared AST child enumeration with an explicit stack, preserving return order and nested callable boundaries.\n\nRefs #1065.\n\nCo-authored-by: rudycelekli <47457359+rudycelekli@users.noreply.github.com>\nCo-authored-by: N0zoM1z0 <161784452+N0zoM1z0@users.noreply.github.com>", - "parents": ["f4a0c1ce95375c1661ca95b414829113a10298b8"], - "authors": [ - { - "name": "Rudy Mizrahi Celekli", - "email": "47457359+rudycelekli@users.noreply.github.com", - "user": { - "login": "rudycelekli", - "__typename": "User" - } - }, - { - "name": "N0zoM1z0", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1368] - }, - { - "sha": "6375ccaf04b4835cc67080ee1ecd91d1fc46645c", - "subject": "perf(native): record macOS command provenance once in its Evidence (#1430)", - "body": "perf(native): record macOS command provenance once in its Evidence (#1430)\n\ninspect_macho, inspect_signature, inspect_plist, list_architectures and\ndemangle_swift already return their command provenance inside the\nnormalized result. The provider also copied the same array into\nraw_result, so every response carried it twice. raw_result now stays\nnull, as docs/mcp-contracts.md describes for results without a distinct\nprovider representation.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["c29931ce81dc530d2623ec992714a70b1f3e50e4"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1430] - }, - { - "sha": "0b9815b6e7080081d8fd426ad9710aee36761afa", - "subject": "docs(skill): save CLI application Evidence and read a summary view (#1429)", - "body": "docs(skill): save CLI application Evidence and read a summary view (#1429)\n\nThe skill's CLI fallback printed the complete application Evidence to\nstdout. A real ASAR produces hundreds of megabytes (334 MB for Obsidian),\nwhich an agent then reads into its context. Save the Evidence to a file\nand project a summary or module page with inspect-analysis-view instead.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["6375ccaf04b4835cc67080ee1ecd91d1fc46645c"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1429] - }, - { - "sha": "dc5af6d68f74155d32a0be957c88afb0ee4be699", - "subject": "perf(mcp): reuse output validators across catalog refreshes (#1433)", - "body": "perf(mcp): reuse output validators across catalog refreshes (#1433)\n\nAdvertise content- and dialect-bound identities for self-contained output schemas so the SDK can reuse unchanged Ajv validators after complete tools/list refreshes. Preserve explicit IDs and relative reference bases.\n\nVerify changed schemas, availability transitions, reconnects, numeric and selector constraints, explicit IDs, relative references, and advertised dialects through the pinned SDK boundaries.\n\nRefs #1065, #723", - "parents": ["0b9815b6e7080081d8fd426ad9710aee36761afa"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1433] - }, - { - "sha": "0a14ca41b46e42d36d46ba07384ff13a7a97456d", - "subject": "fix(javascript): preserve effects through yielded array references (#1437)", - "body": "fix(javascript): preserve effects through yielded array references (#1437)", - "parents": ["dc5af6d68f74155d32a0be957c88afb0ee4be699"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1437] - }, - { - "sha": "ce16f7bc951180b68707fc8cec7e20a0511bb5b3", - "subject": "test(native): verify macOS provenance through real CLI and MCP", - "body": "test(native): verify macOS provenance through real CLI and MCP\n\nVerify five native operations through the public CLI and real SDK stdio MCP using a source-built macOS fixture. Retain normalized provenance, response parity and unchanged input bytes.\n\nRefs #1430, #1065, #723.", - "parents": ["0a14ca41b46e42d36d46ba07384ff13a7a97456d"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1436] - }, - { - "sha": "bb6fa1c6f500c6b6af42f1e3f72bd42c1dce91f6", - "subject": "docs(process): verify independent full-report hashing budgets (#1440)", - "body": "docs(process): verify independent full-report hashing budgets (#1440)", - "parents": ["ce16f7bc951180b68707fc8cec7e20a0511bb5b3"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1440] - }, - { - "sha": "eeb83f65817819644af8e6fbf8a120227dfb88d4", - "subject": "perf(cli): defer Playwright and isomorphic-git until a command needs them", - "body": "perf(cli): defer Playwright and isomorphic-git until a command needs them\n\nLoad browser composition after CLI scenario validation and load Git support only for local reference trees with Git metadata. Preserve default outputs and actual command behavior.\n\nRefs #1065.\n\nCo-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>", - "parents": ["bb6fa1c6f500c6b6af42f1e3f72bd42c1dce91f6"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - } - ], - "pullRequests": [1439] - }, - { - "sha": "33b9b31a6fb50cc3e6f4591d0395dbba15b51f13", - "subject": "perf(javascript): index change-graph nodes once per comparison", - "body": "perf(javascript): index change-graph nodes once per comparison\n\nResolve each compared graph node through a per-side index while preserving right-hand evidence selection and complete comparison results.\n\nRefs #1065.\n\nCo-authored-by: keemsisi <7439375+keemsisi@users.noreply.github.com>", - "parents": ["eeb83f65817819644af8e6fbf8a120227dfb88d4"], - "authors": [ - { - "name": "keemsisi", - "email": "keemsisi@gmail.com", - "user": { - "login": "keemsisi", - "__typename": "User" - } - }, - { - "name": "keemsisi", - "email": "7439375+keemsisi@users.noreply.github.com", - "user": { - "login": "keemsisi", - "__typename": "User" - } - } - ], - "pullRequests": [1434] - }, - { - "sha": "e09cfe9b5970d75da478c9dd741451cc2be5c91a", - "subject": "fix(javascript): invalidate references stored through property targets (#1445)", - "body": "fix(javascript): invalidate references stored through property targets (#1445)\n\n* fix(javascript): invalidate references stored through property targets\n\n* refactor(javascript): share rest keys and return-shape fixtures", - "parents": ["33b9b31a6fb50cc3e6f4591d0395dbba15b51f13"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1445] - }, - { - "sha": "be6863e9a16bcc3a09d87c50981e69292795a512", - "subject": "feat(ghidra): support native PE DLLs on Windows", - "body": "feat(ghidra): support native PE DLLs on Windows\n", - "parents": ["411498d45f860eba2fbc9d7051af20237b7a4cb1"], - "authors": [ - { - "name": "kvalls", - "email": "95490470+kvalls@users.noreply.github.com", - "user": { - "login": "kvalls", - "__typename": "User" - } - } - ], - "pullRequests": [1303] - }, - { - "sha": "941dc425ca12736504227edc084613c0d3612659", - "subject": "chore: merge main into Windows DLL support branch", - "body": "chore: merge main into Windows DLL support branch\n", - "parents": [ - "be6863e9a16bcc3a09d87c50981e69292795a512", - "33b9b31a6fb50cc3e6f4591d0395dbba15b51f13" - ], - "authors": [ - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - } - ], - "pullRequests": [1303] - }, - { - "sha": "7633dd8d5dcb94eb5c2fca8b69858949c51b0eaf", - "subject": "fix(ghidra): publish Windows verification success after cleanup", - "body": "fix(ghidra): publish Windows verification success after cleanup\n", - "parents": ["941dc425ca12736504227edc084613c0d3612659"], - "authors": [ - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - } - ], - "pullRequests": [1303] - }, - { - "sha": "ea1dbda1c747400fe2228c1802a3721995216277", - "subject": "test(ghidra): share result projection client setup", - "body": "test(ghidra): share result projection client setup\n", - "parents": ["7633dd8d5dcb94eb5c2fca8b69858949c51b0eaf"], - "authors": [ - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - } - ], - "pullRequests": [1303] - }, - { - "sha": "a957f397ad3c7a66756dba6aae29c3de2e8d822e", - "subject": "Merge pull request #1303 from kvalls/codex/windows-ghidra-native-dlls", - "body": "Merge pull request #1303 from kvalls/codex/windows-ghidra-native-dlls\n\nfeat(ghidra): support native PE DLLs on Windows", - "parents": [ - "e09cfe9b5970d75da478c9dd741451cc2be5c91a", - "ea1dbda1c747400fe2228c1802a3721995216277" - ], - "authors": [ - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - } - ], - "pullRequests": [1303] - }, - { - "sha": "e10c934d5a756c1a4c7b547ebd02c403ddfde7b8", - "subject": "fix(ghidra): keep the cross-format branch callee multi-block", - "body": "fix(ghidra): keep the cross-format branch callee multi-block\n\nThe cross-format oracle requires a callee whose recovered control flow\nhas more than one basic block, and rea_cross_branch provided it through\na symmetric if/else of tail calls. Clang 21 folds that shape into a\nconditional negate plus one tail branch, a single basic block, so the\nlane rejected a correct Ghidra analysis of the fixture.\n\nGive the branch a loop whose trip count depends on a volatile global:\nno compiler can eliminate the backedge, and the callee stays multi-block\nat every optimization level on every toolchain.\n", - "parents": ["08ec2bf82fa88f5e8caa2b7da9093636731dc55c"], - "authors": [ - { - "name": "GRAB Racem", - "email": "racem.grab@etu.univ-lyon1.fr", - "user": { - "login": "BaaRai", - "__typename": "User" - } - } - ], - "pullRequests": [1382] - }, - { - "sha": "40f632a155bff2defdea09e467229c703bc0b0e9", - "subject": "ci: re-run the suite after the main-branch shard flake", - "body": "ci: re-run the suite after the main-branch shard flake\n\nThe failed shard is the JavaScriptSemanticGraphBuilder short-circuit\nmutation test, which also failed on main run 38003459598 at the same\nbase commit (08ec2bf8) before this branch started CI, and passed on\nmain run 38003459600 minutes later at the same commit.\n", - "parents": ["e10c934d5a756c1a4c7b547ebd02c403ddfde7b8"], - "authors": [ - { - "name": "GRAB Racem", - "email": "racem.grab@etu.univ-lyon1.fr", - "user": { - "login": "BaaRai", - "__typename": "User" - } - } - ], - "pullRequests": [1382] - }, - { - "sha": "e17290cd2a17931d7a2af70f74b76b94276bd788", - "subject": "ci: re-run the suite on the corrected main checkpoint", - "body": "ci: re-run the suite on the corrected main checkpoint\n\nb8a8190b restored the guarded-mutation uncertainty the failing test\nencodes, so the shard should pass against the new merge base.\n", - "parents": ["40f632a155bff2defdea09e467229c703bc0b0e9"], - "authors": [ - { - "name": "GRAB Racem", - "email": "racem.grab@etu.univ-lyon1.fr", - "user": { - "login": "BaaRai", - "__typename": "User" - } - } - ], - "pullRequests": [1382] - }, - { - "sha": "f1231d4a2c43dc2d8cc6d5254ee0201771086508", - "subject": "Merge pull request #1382 from BaaRai/fix/cross-branch-multiblock-callee", - "body": "Merge pull request #1382 from BaaRai/fix/cross-branch-multiblock-callee\n\nfix(ghidra): keep the cross-format branch callee multi-block", - "parents": [ - "a957f397ad3c7a66756dba6aae29c3de2e8d822e", - "e17290cd2a17931d7a2af70f74b76b94276bd788" - ], - "authors": [ - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - } - ], - "pullRequests": [1382] - }, - { - "sha": "e4a8e0b728154fe0bf181684ccd0d73df45cf4bf", - "subject": "fix(javascript): recognize Electron APIs through renamed bindings", - "body": "fix(javascript): recognize Electron APIs through renamed bindings\n\nElectron recognition matched callee spellings, so a bundler rename such as\nesbuild's `import { ipcMain as ipcMain2 } from \"electron\"`, or a destructured\n`const { contextBridge: bridge } = require(\"electron\")`, hid every IPC\nhandler, BrowserWindow, contextBridge and utility process behind it.\n\nResolve each call and construction root lexically to its Electron import or\nrequire origin, and classify the callee under that export's name. Shadowed\nlocals keep their own meaning.\n\nOn Hermes Desktop v0.21.6, whose main process is one esbuild ESM bundle,\nrecognized main IPC handlers rise from 1 to 204, BrowserWindow constructions\nfrom 0 to 11, and paired renderer transmissions from 1 to 201.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) \nClaude-Session: https://claude.ai/code/session_01XPY2GmufMNGQKoEgRUx1pd\n", - "parents": ["7aa4d768eb15317a63a476431ed75bafec086033"], - "authors": [ - { - "name": "Claude", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1391] - }, - { - "sha": "0d2082d36b8bed3cda5daa22adee2163652fc511", - "subject": "fix(javascript): recognize unchanged var and let Electron aliases", - "body": "fix(javascript): recognize unchanged var and let Electron aliases\n", - "parents": ["e4a8e0b728154fe0bf181684ccd0d73df45cf4bf"], - "authors": [ - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - } - ], - "pullRequests": [1391] - }, - { - "sha": "817efaca9aafc4a72884773ff8b93a32cb6e3350", - "subject": "Merge pull request #1391 from marnixpluim/fix/electron-import-aliases", - "body": "Merge pull request #1391 from marnixpluim/fix/electron-import-aliases\n\nfix(javascript): recognize Electron APIs through renamed bindings", - "parents": [ - "f1231d4a2c43dc2d8cc6d5254ee0201771086508", - "0d2082d36b8bed3cda5daa22adee2163652fc511" - ], - "authors": [ - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - } - ], - "pullRequests": [1391] - }, - { - "sha": "66863b609fe5bdbb46b8634399ea08439a94a9f4", - "subject": "test(javascript): reuse comparison node fixtures", - "body": "test(javascript): reuse comparison node fixtures\n\nUse the established typed graph fixture constructor while retaining right-hand comparison provenance assertions. Restore the unchanged duplicate-code gate on combined main.\n\nCloses #1446. Refs #1434, #1443, #1065.", - "parents": ["817efaca9aafc4a72884773ff8b93a32cb6e3350"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1448] - }, - { - "sha": "1ec490f36180cf6d3a8f353e9e43920dbd81ece0", - "subject": "fix(javascript): stop replaying earlier writes for each object property write", - "body": "fix(javascript): stop replaying earlier writes for each object property write\n\nRepeated property writes to one object made member-mutation collection\ncubic. Each write evaluated its target binding to rule out a primitive,\nand every evaluation folded all earlier mutation paths, copying every\nslot once per path. 2,000 writes to one object took 27 s and 4,000 took\n203 s.\n\n- A recorded write always leaves a non-primitive binding value, so only\n the first write to a binding needs the primitive check.\n- Apply mutation paths per slot in one pass with the same ordering\n semantics instead of one full slot copy per path.\n\nCo-authored-by: Claude Opus 5.5 \nCo-authored-by: N0zoM1z0 <161784452+N0zoM1z0@users.noreply.github.com>", - "parents": ["66863b609fe5bdbb46b8634399ea08439a94a9f4"], - "authors": [ - { - "name": "Zeynel", - "email": "137368801+zeynelacikgoez@users.noreply.github.com", - "user": { - "login": "zeynelacikgoez", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - }, - { - "name": "N0zoM1z0", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1444] - }, - { - "sha": "c89c8f53187aac02e87f0ca11e3dd120b8c7efef", - "subject": "docs(mcp): record real Windows first-query recovery", - "body": "docs(mcp): record real Windows first-query recovery", - "parents": ["1ec490f36180cf6d3a8f353e9e43920dbd81ece0"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1452] - }, - { - "sha": "2781cad20125ff3a210b795f60620b048e1bbe9b", - "subject": "perf(process): stop padding rendered terminal lines to full width (#1450)", - "body": "perf(process): stop padding rendered terminal lines to full width (#1450)\n\nRendered frames padded every visible row with trailing spaces to the\nterminal width. Blank rows cost a full row each and every frame repeats\nthem, so the padding made up 14-39% of capture Evidence (2 KB of sparse\noutput produced 228 KB). The padding carried no information: columns is\nrecorded and serialized_state keeps the exact terminal state.\n\nLines are now trimmed after normalization, so line.padEnd(columns)\nrestores the previous value. The comparison contract commits\nrendered_line_format so older padded captures do not compare as the\nsame contract.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["c89c8f53187aac02e87f0ca11e3dd120b8c7efef"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1450] - }, - { - "sha": "ef96657d6ba0c1f22ebdb1e6bd4d9a6ac9335002", - "subject": "perf(javascript): hash each semantic evidence context once (#1457)", - "body": "perf(javascript): hash each semantic evidence context once (#1457)\n\nThe semantic graph's evidence-context registry canonicalized the full\nprovenance context three times for every node, relation, unknown and\nfingerprint: once to hash its ID and twice more to compare against the\nstored row. A file has only a few distinct contexts, so nearly all of\nthat work repeated a known answer.\n\nInterning now keys contexts by their canonical text. Each fact\ncanonicalizes once, and only a new context is hashed and checked for a\ndigest collision. IDs and output are unchanged; Obsidian's 334 MB\nEvidence is byte-identical and analysis drops from about 47.0 s to\n44.4 s.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["2781cad20125ff3a210b795f60620b048e1bbe9b"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1457] - }, - { - "sha": "b118f044926ae6b4880c4214621ae6c5b2a71f17", - "subject": "perf(apple): stop repeating the archive path in Interface Builder evidence (#1460)", - "body": "perf(apple): stop repeating the archive path in Interface Builder evidence (#1460)\n\nEvery Interface Builder node and edge evidence record prefixed its\ndescription with the archive's relative path, which artifact_path in the\nsame record already states. Bundles carry thousands of objects across\nlocalized nibs, so the repeated path made up 6-10% of\ndecode_interface_builder output (XLD: 7.38 MB to 6.62 MB).\n\nDescriptions now name only the decoded item, such as \"object 81\" or\n\"outlet o_quality\".\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["ef96657d6ba0c1f22ebdb1e6bd4d9a6ac9335002"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1460] - }, - { - "sha": "696fb834b8873ac9f6df0c4d45377bdd7c3c5762", - "subject": "fix(skills): expose authored skill to repository discovery", - "body": "fix(skills): expose authored skill to repository discovery\n", - "parents": ["c89c8f53187aac02e87f0ca11e3dd120b8c7efef"], - "authors": [ - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - } - ], - "pullRequests": [1463] - }, - { - "sha": "28d3cb545c720722f397412054ffa337ba072df5", - "subject": "Merge pull request #1463 from morluto/codex/fix-skill-source-discovery", - "body": "Merge pull request #1463 from morluto/codex/fix-skill-source-discovery\n\nfix(skills): expose authored skill to repository discovery", - "parents": [ - "b118f044926ae6b4880c4214621ae6c5b2a71f17", - "696fb834b8873ac9f6df0c4d45377bdd7c3c5762" - ], - "authors": [ - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - } - ], - "pullRequests": [1463] - }, - { - "sha": "ea923287751043c7acfaa35a0acd10fe32f785d6", - "subject": "fix(mcp): validate doctor probe against its discovered output contract (#1461)", - "body": "fix(mcp): validate doctor probe against its discovered output contract (#1461)\n\nValidate the target-free probe against the named definition discovered from the complete production catalog. Preserve initialized server and inventory observations when the SDK rejects the probe, and retain the schema failure reason, absolute deadline and owned-child cleanup.\n\nThe negative stdio replay regression fails on original main and passes the fix; actual production-boundary fault injection confirms rejection. Nine doctor/help tests, serial full static checks and real small-target CLI/MCP parity pass. Successful doctor reports remain byte-identical. No performance or model-token reduction is claimed.\n\nCloses #1454. Refs #1065, #723, #1433.", - "parents": ["28d3cb545c720722f397412054ffa337ba072df5"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1461] - }, - { - "sha": "4e3d3354397374116577555200319975fc2ff86e", - "subject": "test(android): retain incomplete cleanup failure reasons (#1443)", - "body": "test(android): retain incomplete cleanup failure reasons (#1443)\n\nInclude the full stop disposition in the fixture assertion message, so incomplete owned teardown retains its typed reason in Vitest failure reporters. Preserve the existing cleanup requirement without retries or relaxed ownership checks.\n\nSeven process-boundary tests, full serial typecheck/lint/duplication/format checks, and 19 final-head CI checks pass after integrating the combined-main fixture fix. A controlled failure-rendering probe verifies that the explicit message preserves the reason. The original CI cleanup failure remains unreproduced; this is diagnostic work with a synthetic JADX producer, not a root-cause or real-engine fix.\n\nRefs #1441, #1446, #1448, #1065.", - "parents": ["ea923287751043c7acfaa35a0acd10fe32f785d6"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1443] - }, - { - "sha": "78e1308f49492011be448c9b35ce16d98d60c4ad", - "subject": "docs(process): clarify normalized terminal line representation", - "body": "docs(process): clarify normalized terminal line representation", - "parents": ["4e3d3354397374116577555200319975fc2ff86e"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1465] - }, - { - "sha": "79f6756239105164eac7aa5618844ffd9bdf41e5", - "subject": "docs(website): link the Discord community and REA on X (#1469)", - "body": "docs(website): link the Discord community and REA on X (#1469)\n\nAdd an X link beside the GitHub and Discord header icons on every content\npage, name the footer links \"Join the community\" and \"Follow us on X\", and\nclose the homepage with a \"Join the community\" section.\n\nOn narrow screens, pad the footer so the floating Top link no longer\ncovers its last row of links.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["78e1308f49492011be448c9b35ce16d98d60c4ad"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1469] - }, - { - "sha": "934ffd28d15f4fbe6687ca8986a949e1b41a07d1", - "subject": "perf(javascript): derive the application graph ID once", - "body": "perf(javascript): derive the application graph ID once\n\ncreateJavaScriptApplicationGraph hashed the whole graph to derive its\ngraph_id, then parsed it with the public schema, whose invariant check\nhashed the same content again to verify that ID. Validate the content\nwith every other invariant first, then derive graph_id once from the\nvalidated copy. The public schema still verifies graph_id for stored\nand untrusted graphs, and created graphs are unchanged.", - "parents": ["79f6756239105164eac7aa5618844ffd9bdf41e5"], - "authors": [ - { - "name": "keemsisi", - "email": "keemsisi@gmail.com", - "user": { - "login": "keemsisi", - "__typename": "User" - } - } - ], - "pullRequests": [1458] - }, - { - "sha": "aa23ec883f6c7101db184767a1f48cddb636d597", - "subject": "feat(clients): register Qwen Code during setup (#1415)", - "body": "feat(clients): register Qwen Code during setup (#1415)\n\n* feat(clients): register Qwen Code during setup\n\n* fix(clients): honor Qwen home and shared skill discovery\n\n---------\n\nCo-authored-by: morluto <76467478+morluto@users.noreply.github.com>", - "parents": ["934ffd28d15f4fbe6687ca8986a949e1b41a07d1"], - "authors": [ - { - "name": "ๆ˜“่‰ฏ", - "email": "1204183885@qq.com", - "user": { - "login": "yiliang114", - "__typename": "User" - } - }, - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - } - ], - "pullRequests": [1415] - }, - { - "sha": "3c7b176a3df18b3971d9ea9ff40f7ebbd85fa40a", - "subject": "perf(artifacts): deliver the inspected artifact graph once (#1473)", - "body": "perf(artifacts): deliver the inspected artifact graph once (#1473)\n\ninspect_artifact nested the complete inventory Evidence and then restated\nevery artifact node and occurrence as an observation and every edge as a\nderived relationship. No caller reads those copies; comparison and tests\nuse the nested inventory Evidence. On Transmission.app the result shrinks\nfrom 2.46 MB to 1.10 MB.\n\nObservations keep the root manifest and integrity findings.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["aa23ec883f6c7101db184767a1f48cddb636d597"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1473] - }, - { - "sha": "7296f2b5bfff921b2ca16f942a09616c8adf2b3f", - "subject": "perf(javascript)!: stop repeating the semantic identifier strategy per fact (#1474)", - "body": "perf(javascript)!: stop repeating the semantic identifier strategy per fact (#1474)\n\nEvery semantic graph node and relation carried an identifier_strategy\nobject whose schema admits exactly one value per record type. The\nconstant made up about 9% of analyze_javascript_application output\n(Obsidian app.asar: 12.04 MB to 10.96 MB), and semantic traces repeated\nit on every returned fact.\n\nThe node_id and relation_id schema descriptions now state how each\nidentifier is derived.\n\nBREAKING CHANGE: Semantic graph nodes and relations no longer include\nidentifier_strategy, and relation IDs no longer hash that constant.\nEvidence recorded by earlier versions does not validate against the new\nsemantic graph schema.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["3c7b176a3df18b3971d9ea9ff40f7ebbd85fa40a"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1474] - }, - { - "sha": "1f0775684b2cf8089bddfa7e2f0ee9aa6517c8a8", - "subject": "fix(artifacts): keep case-distinct archive names in inventory (#1480)", - "body": "fix(artifacts): keep case-distinct archive names in inventory (#1480)\n\nZIP member names are case-sensitive. Inventory was folding them with a\nfilesystem case rule, so shrunk APKs never became evidence for the Android\napplication graph. Logical registration now keeps both spellings and records\nan English Unicode case-folding limitation. Extraction fails only when the\ndestination directory already holds the other spelling.\n\nCo-authored-by: Cursor Agent ", - "parents": ["7296f2b5bfff921b2ca16f942a09616c8adf2b3f"], - "authors": [ - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - }, - { - "name": "Cursor Agent", - "email": "cursoragent@cursor.com", - "user": { - "login": "cursoragent", - "__typename": "User" - } - } - ], - "pullRequests": [1480] - }, - { - "sha": "b09d02d93cbadfa0ced21e7c489c7d47fb317228", - "subject": "feat(website): add a blog for methods and project notes", - "body": "feat(website): add a blog for methods and project notes\n", - "parents": ["1f0775684b2cf8089bddfa7e2f0ee9aa6517c8a8"], - "authors": [ - { - "name": "N0zoM1z0", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1475] - }, - { - "sha": "130ffdf6bc89f3b1a438034f118c38fae306951e", - "subject": "docs(website): outline the Touhou reconstruction workflow", - "body": "docs(website): outline the Touhou reconstruction workflow\n", - "parents": ["b09d02d93cbadfa0ced21e7c489c7d47fb317228"], - "authors": [ - { - "name": "N0zoM1z0", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1475] - }, - { - "sha": "7df20506065531749f9e040e59a28015cda10324", - "subject": "docs(website): write the Touhou reconstruction essay", - "body": "docs(website): write the Touhou reconstruction essay\n", - "parents": ["130ffdf6bc89f3b1a438034f118c38fae306951e"], - "authors": [ - { - "name": "N0zoM1z0", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1475] - }, - { - "sha": "ed200a23026ea9730cae85367699c17dfe5f0ab6", - "subject": "docs(website): emphasize the reconstruction essay takeaways", - "body": "docs(website): emphasize the reconstruction essay takeaways\n", - "parents": ["7df20506065531749f9e040e59a28015cda10324"], - "authors": [ - { - "name": "N0zoM1z0", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1475] - }, - { - "sha": "cf6957e796b241d81bc1cd8e58354c906a3d0467", - "subject": "feat(website): link the Blog from the homepage introduction", - "body": "feat(website): link the Blog from the homepage introduction\n", - "parents": ["ed200a23026ea9730cae85367699c17dfe5f0ab6"], - "authors": [ - { - "name": "N0zoM1z0", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1475] - }, - { - "sha": "3ea0233342cb15c2a58b5707bf9962d1d28b72d5", - "subject": "docs(website): simplify the Blog introduction", - "body": "docs(website): simplify the Blog introduction\n", - "parents": ["cf6957e796b241d81bc1cd8e58354c906a3d0467"], - "authors": [ - { - "name": "N0zoM1z0", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1475] - }, - { - "sha": "07d416505cb6836614079e3dace8dc9015197bf2", - "subject": "docs(website): finalize the Touhou essay for publication", - "body": "docs(website): finalize the Touhou essay for publication\n", - "parents": ["3ea0233342cb15c2a58b5707bf9962d1d28b72d5"], - "authors": [ - { - "name": "N0zoM1z0", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1475] - }, - { - "sha": "cbcba2902dd8caa206d2c5858d73449b87700da0", - "subject": "docs(website): align Blog community links with the site", - "body": "docs(website): align Blog community links with the site\n", - "parents": ["07d416505cb6836614079e3dace8dc9015197bf2"], - "authors": [ - { - "name": "N0zoM1z0", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1475] - }, - { - "sha": "b12d0c6361ace4b150e21f7e9a90bdb4211a2a49", - "subject": "test(artifacts): respect destination filesystem case sensitivity", - "body": "test(artifacts): respect destination filesystem case sensitivity\n", - "parents": ["cbcba2902dd8caa206d2c5858d73449b87700da0"], - "authors": [ - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - } - ], - "pullRequests": [] - }, - { - "sha": "2596f8da142cde4c92677420df438848c34ea0c3", - "subject": "test(android): retry verified cleanup during fixture teardown", - "body": "test(android): retry verified cleanup during fixture teardown\n", - "parents": ["b12d0c6361ace4b150e21f7e9a90bdb4211a2a49"], - "authors": [ - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - } - ], - "pullRequests": [] - }, - { - "sha": "5f6bb7a5bae4e6d8809823920d67e52d6ba9f963", - "subject": "perf(apple): state each NIB object's class, label, and ID once (#1477)", - "body": "perf(apple): state each NIB object's class, label, and ID once (#1477)\n\nThe NIBArchive projection synthesizes customClass, label, and objectID so\nits records share the ibtool dictionary parser. The parser then returned\nthose values as class_name, name, and the object ID, and the graph node\nkept the synthesized copies in attributes as well. Attributes now omit a\nkey whose value its canonical field already carries; differing authored\nvalues stay. Transmission.app decode_interface_builder output shrinks\nfrom 6.45 MB to 6.14 MB.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["2596f8da142cde4c92677420df438848c34ea0c3"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1477] - }, - { - "sha": "9defed97254f5a882643154d92db5e65bad19137", - "subject": "perf(mcp): stop advertising placeholder input descriptions (#1479)", - "body": "perf(mcp): stop advertising placeholder input descriptions (#1479)\n\nInput schema presentation gave every undescribed property a generic\n\"Value for .\" sentence. That only restates the property name, yet\nit covered 1,958 properties: 70 KB of the 522 KB of advertised input\nschemas that clients load into model context. Authored descriptions,\nreferenced descriptions, and the name-pattern sentences that add meaning\n(maximums, digests, paths, Evidence IDs) remain; other properties now\nadvertise no description.\n\nThe schema validity test now rejects placeholder descriptions instead of\nrequiring a description on every property.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["5f6bb7a5bae4e6d8809823920d67e52d6ba9f963"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1479] - }, - { - "sha": "782e0147cd87aeb2aca12278ebb852f994d877ad", - "subject": "fix(javascript): retain returned-reference mutation uncertainty (#1471)", - "body": "fix(javascript): retain returned-reference mutation uncertainty (#1471)", - "parents": ["9defed97254f5a882643154d92db5e65bad19137"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1471] - }, - { - "sha": "1f692c83e2e6dcf175f32c8ac532b77eb556b4d6", - "subject": "perf(artifacts): stop repeating every artifact path as Evidence locations (#1492)", - "body": "perf(artifacts): stop repeating every artifact path as Evidence locations (#1492)\n\ninventory_artifact, inspect_artifact, and extract_artifact copied each\noccurrence or extracted file path into Evidence locations, although the\nresult already names every one. inspect_artifact did so twice, in its own\nEvidence and in the nested inventory Evidence. Like other whole-target\nEvidence, these now report no locations.\n\nVisual Studio Code.app: inspect_artifact 15.37 MB to 13.07 MB,\nextract_artifact 1.40 MB to 1.06 MB.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["782e0147cd87aeb2aca12278ebb852f994d877ad"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1492] - }, - { - "sha": "a0e5e9db2b9e3645295e1c060c01d1f24aa7e277", - "subject": "perf(artifacts)!: name each edge's child through its occurrence (#1493)", - "body": "perf(artifacts)!: name each edge's child through its occurrence (#1493)\n\nEvery inventory edge is created from one occurrence and copied that\noccurrence's artifact_id and logical_path as child_artifact_id and\nlogical_path. Edges now keep the occurrence_id reference alone. Edge IDs\nstill hash the same child and path, read from the occurrence, so they are\nunchanged; validation and artifact comparison read the occurrence too.\n\ninspect_artifact output: Transmission.app 1.10 MB to 0.97 MB, Visual\nStudio Code.app 15.37 MB to 13.48 MB.\n\nBREAKING CHANGE: Artifact inventory edges no longer include\nchild_artifact_id or logical_path; read them from the occurrence named by\noccurrence_id. The graph commitment changes, so inventory Evidence\nrecorded by earlier versions no longer validates.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["1f692c83e2e6dcf175f32c8ac532b77eb556b4d6"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1493] - }, - { - "sha": "f970b886aace516383caaa6d974f9df63faff340", - "subject": "feat: add Hermes as a supported MCP client (#1403)", - "body": "feat: add Hermes as a supported MCP client (#1403)\n\n* feat: add Hermes as a supported MCP client\n\nHermes Agent reads stdio MCP servers from `mcp_servers.` in\n`config.yaml`. REA had no Hermes client, so setup could not register it and\nHermes users had to wire the server up by hand.\n\n- SupportedClients: add the `hermes` format and client definition, resolving\n the config path from HERMES_HOME, else the platform default that Hermes's own\n resolver uses (LOCALAPPDATA/hermes on Windows, ~/.hermes elsewhere), including\n HERMES_DATA_DIR_SUFFIX.\n- ClientConfigurationDocument: parse and serialize Hermes YAML, upserting the\n rea entry into the parsed document so user comments and unrelated settings are\n preserved; emit `enabled: true` since Hermes connects entries unless disabled.\n- ClientRegistrationStatus: forward the Hermes location variables so status\n checks resolve the same path as setup.\n- Tests: cover path resolution on both platforms and the register/read/uninstall\n round trip, and clear the Hermes location variables between tests.\n\n- delilah ๐ŸŒธ\n\n* docs: document the Hermes client and its config path\n\n- delilah ๐ŸŒธ\n\n* refactor(setup): resolve skill destinations per client\n\n* fix(setup): install Hermes skills in the active profile\n\n* fix(setup): identify each client skill action uniquely\n\n---------\n\nCo-authored-by: morluto <76467478+morluto@users.noreply.github.com>", - "parents": ["a0e5e9db2b9e3645295e1c060c01d1f24aa7e277"], - "authors": [ - { - "name": "zayd / cold", - "email": "zaydkhan3@gmail.com", - "user": { - "login": "zaydiscold", - "__typename": "User" - } - }, - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - } - ], - "pullRequests": [1403] - }, - { - "sha": "9e22da845bf8b447f81539e0ba57d5deb59e9103", - "subject": "feat(setup): add native Pi client support (#1376)", - "body": "feat(setup): add native Pi client support (#1376)\n\n* feat(setup): add native Pi client support\n\n* fix(setup): isolate invalid Pi agent directory overrides\n\nKeep malformed Pi path evidence on its client entry so unrelated selected clients can complete setup and doctor. Preserve explicit Pi rejection and block filesystem operations rather than falling back to another directory.\n\n* fix(setup): parse Pi configuration as strict JSON\n\nPi's installed MCP loader reads mcp.json with a bare JSON.parse and no\nBOM tolerance, so comments, trailing commas, a BOM, or an empty existing\nfile yield loader errors and no servers. Parsing the Pi dialect with\nobjectSchema.parse(JSON.parse(text)) before the shared empty/JSONC\nshortcut rejects those files at every mutation boundary instead of\nreporting configured registrations Pi cannot load. A missing file still\ninitializes a fresh strict-JSON document, other dialects keep their\nJSONC/BOM/empty tolerance, and malformed files are never rewritten.\n\n---------\n\nCo-authored-by: morluto <76467478+morluto@users.noreply.github.com>", - "parents": ["f970b886aace516383caaa6d974f9df63faff340"], - "authors": [ - { - "name": "Richard A Steenbergen", - "email": "38380971+rasatpetabit@users.noreply.github.com", - "user": { - "login": "rasatpetabit", - "__typename": "User" - } - }, - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - } - ], - "pullRequests": [1376] - }, - { - "sha": "983b070d4d5c6179526f3b24e20c9d344388b786", - "subject": "fix(artifacts): record each case collision once at its diverging segment (#1505)", - "body": "fix(artifacts): record each case collision once at its diverging segment (#1505)\n\nInventory paired every path under one case spelling with every path under\neach other spelling and listed all of them on each occurrence. An archive\nwith Foo/ and foo/ subtrees of N files each produced N-entry lists on 2N\noccurrences: 4,000 such ZIP members yielded a 120 MB inspect_artifact\nresult and close to 1 GB of memory. The trie walks also recursed once per\npath component, so a ZIP name with tens of thousands of components threw\nRangeError.\n\nA collision is now recorded at the segment where spellings diverge and\nshared down that subtree by an iterative walk. Each occurrence names the\ncolliding prefix and the first other spelling, plus a count of further\nspellings, each of which is its own occurrence.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["9e22da845bf8b447f81539e0ba57d5deb59e9103"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1505] - }, - { - "sha": "f63f12d8ff2ba1f0e832ff86e87dbf37d4a5e325", - "subject": "docs: align the Indonesian README with the other translations (#1512)", - "body": "docs: align the Indonesian README with the other translations (#1512)\n\nKeep the Bahasa Indonesia onboarding text from #1508, and fix the formatting\nthat left it outside the shared README layout: drop the leading space, point\nin-page links at the translated headings, align the analysis table, and link\nBahasa Indonesia from every language selector.\n\nCo-authored-by: Cursor Agent \nCo-authored-by: Dev Cee <24010110166@universitasbumigora.ac.id>", - "parents": ["983b070d4d5c6179526f3b24e20c9d344388b786"], - "authors": [ - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - }, - { - "name": "Cursor Agent", - "email": "cursoragent@cursor.com", - "user": { - "login": "cursoragent", - "__typename": "User" - } - }, - { - "name": "Dev Cee", - "email": "24010110166@universitasbumigora.ac.id", - "user": { - "login": "inii-sayaa", - "__typename": "User" - } - } - ], - "pullRequests": [1512] - }, - { - "sha": "911323c5dd27f4bc924b74c803587164f79f4984", - "subject": "fix(native): page every retained function dossier collection (#1507)", - "body": "fix(native): page every retained function dossier collection (#1507)\n\ninspect_analysis_view is the recovery path when an analyze_function\ndossier exceeds the MCP response budget, but its native facets covered\nonly procedure, pseudocode, assembly, callers/callees, references, and\nvalue flow. Basic blocks, comments, unresolved calls, referenced strings\nand names, and the native API record could not be read from retained\nEvidence at all; basic blocks grow with the function just like assembly.\n\nThese are now facets: collections page by rows, and native_api is a\nsingleton. A dossier without an unresolved_calls record reports \"not\nrecorded\" rather than the value-flow failure reason.\n\nRefs #1247 and #1065.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["f63f12d8ff2ba1f0e832ff86e87dbf37d4a5e325"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1507] - }, - { - "sha": "93ca276921cb6bd1ebfa0431369633c0a428bde5", - "subject": "fix(browser): accept HAR files that begin with a byte-order mark (#1509)", - "body": "fix(browser): accept HAR files that begin with a byte-order mark (#1509)\n\nHAR 1.2 lets writers emit a UTF-8 byte-order mark and requires readers to\nignore it. The decoder passed ignoreBOM: true to TextDecoder, which keeps\nthe mark in the decoded text, so a BOM-prefixed export failed as \"HAR is\nmalformed JSON.\" Decoding now uses the default, which skips one leading\nmark. The artifact digest still covers the selected file bytes.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["911323c5dd27f4bc924b74c803587164f79f4984"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1509] - }, - { - "sha": "a936303723939478cbc8ebd7068ce32ef6eb1028", - "subject": "fix(json): name a leading byte-order mark in rejected JSON input (#1510)", - "body": "fix(json): name a leading byte-order mark in rejected JSON input (#1510)\n\nStrict JSON file inputs reject a leading UTF-8 byte-order mark, but the\ndiagnostic was the parser's own message, which quotes the invisible U+FEFF\nas the unexpected token: Unexpected token '', \"{\"invento\"... is not\nvalid JSON. Editors such as Windows PowerShell 5.1 write that mark by\ndefault, and nothing in the message showed it.\n\nCLI JSON files (whole and streamed), Evidence and snapshot JSON files, and\nprocess scenario files now report that the input begins with a UTF-8\nbyte-order mark and how to save it. Acceptance is unchanged.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["93ca276921cb6bd1ebfa0431369633c0a428bde5"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1510] - }, - { - "sha": "2bf812772d7209e31e15198bc3383243ad879f39", - "subject": "fix(apple): bound binary plist expansion before decoding keyed archives (#1515)", - "body": "fix(apple): bound binary plist expansion before decoding keyed archives (#1515)\n\ninspect_keyed_archive passed caller-selected binary plists straight to\nplist.parseBinary, which recurses on every object reference and copies\nshared containers. A 484-byte archive of forty nested [next, next] arrays\ngrew the process past 4 GB until it died with no result, which would also\nend an MCP server. A 125-byte self-referencing array overflowed the stack\nand was reported as an artifact too large to process.\n\nThe iterative reference walk that already guards decode_interface_builder\nnow runs first, with an 8x keyed-archive decode budget. Over-budget depth\nor expansion is a limit; a reference cycle is a malformed archive. Its\n\"decoder\" bounds admit the same layouts plist.parseBinary reads, so\naccepted archives stay accepted. Interface Builder behavior is unchanged.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["a936303723939478cbc8ebd7068ce32ef6eb1028"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1515] - }, - { - "sha": "f51503ef1c4b0b7e8b00bf413d5a4436c8bc1d87", - "subject": "fix(process): normalize scenario replacements literally", - "body": "fix(process): normalize scenario replacements literally\n\ncapture_process_scenario declares normalization patterns as literal text, but\\nreplaceAll expands \\$&\\, \\$\\`, and \\$1\\ in the replacement as a replacement\\npattern. A caller normalizing text that contains a dollar sign silently gets\\nduplicated, spliced, or dropped content in the recorded Evidence instead of\\nthe requested literal replacement.\\n\\nUse split/join, which is literal on both sides and is already the idiom used\\nfor exact-literal scenario rules in browserScenarioNormalization.ts.\n", - "parents": ["2bf812772d7209e31e15198bc3383243ad879f39"], - "authors": [ - { - "name": "openhands", - "email": "madha@algorithmx.ai", - "user": null - } - ], - "pullRequests": [1456] - }, - { - "sha": "2b6f14f528297cf12c776c960af0859f5cfbefbf", - "subject": "fix(process)!: version literal scenario replacement semantics", - "body": "fix(process)!: version literal scenario replacement semantics\n\nKeep caller-selected replacement text literal with a callback, preserving\nempty-search positions instead of changing their split/join behavior.\nCommit the replacement interpretation for captures using custom patterns so\nlegacy records cannot report this producer correction as a target change.\n\nBREAKING CHANGE: Captures with custom normalization patterns use\nliteral-replacements-v1 and cannot be compared with legacy unversioned\npattern captures. Capture both sides with the same replacement semantics;\nlegacy captures remain readable and captures without patterns are unaffected.\n", - "parents": ["f51503ef1c4b0b7e8b00bf413d5a4436c8bc1d87"], - "authors": [ - { - "name": "N0zoM1z0", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1456] - }, - { - "sha": "b6ad1f2c3d0616e83e548efa7afed0107af122d8", - "subject": "feat(mcp): compact input schema profile for size-capped providers (kimi-cli/Moonshot) (#1514)", - "body": "feat(mcp): compact input schema profile for size-capped providers (kimi-cli/Moonshot) (#1514)\n\n* feat(mcp): add compact input schema profile for size-capped providers\n\nMoonshot's function-calling API rejects a request while any single tool\nparameters schema exceeds its literal serialized size cap, so clients\nsuch as kimi-cli fail every request while the default catalog is\nattached (#1484).\n\nAdd an opt-in REA_MCP_INPUT_SCHEMA_PROFILE=compact server presentation.\nEach advertised input schema is rendered within a 13,312-byte budget,\nmeasured to sit below the observed provider cap: annotation prose\n(nested descriptions, examples, defaults, titles) is dropped, repeated\nannotation-free subschemas are shared through schema-local $defs/$ref\nreferences the provider validates without expansion, and the three\nstructurally oversized schemas are advertised in a documented reduced\nform. The canonical catalog, tool set, output schemas, and server-side\ncanonical validation are unchanged; the default full profile is\nbyte-identical to today's advertisement.\n\nBoundary tests pin every compact schema to the budget, keep them valid\nJSON Schema that still accepts every canonical example, hold reduced\npresentations at three or fewer, and verify canonical rejection still\nguards a permissive advertisement. Verified against the real Moonshot\nAPI through kimi-cli: prompts succeed with the compact catalog attached\nwhere the default catalog fails every request with 400.\n\n* fix(mcp): preserve compact schemas through Kimi conversion\n\n---------\n\nCo-authored-by: morluto <76467478+morluto@users.noreply.github.com>", - "parents": ["2b6f14f528297cf12c776c960af0859f5cfbefbf"], - "authors": [ - { - "name": "Haythem Sellami", - "email": "17862704+haythemsellami@users.noreply.github.com", - "user": { - "login": "haythemsellami", - "__typename": "User" - } - }, - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - } - ], - "pullRequests": [1514] - }, - { - "sha": "b25922e4e8fe389cf17c151ccb7b4be4a42824d9", - "subject": "test(clients): verify native Qwen Pi and Hermes workflows (#1511)", - "body": "test(clients): verify native Qwen Pi and Hermes workflows (#1511)", - "parents": ["b6ad1f2c3d0616e83e548efa7afed0107af122d8"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1511] - }, - { - "sha": "7a56fe6260cbda2e4c77e30d143db0e62f211b5b", - "subject": "fix(setup): honor active client configuration and skill roots (#1504)", - "body": "fix(setup): honor active client configuration and skill roots (#1504)\n\n* refactor(setup): resolve skill destinations per client\n\n* fix(setup): honor active client configuration and skill roots\n\n* fix(setup): validate effective client scopes and Gemini trust\n\n* fix(setup): treat empty OpenCode overrides as unset\n\nAn empty OPENCODE_CONFIG_DIR now stays on the XDG directory, and doctor\nand setup inspect global OpenCode files when a custom directory is absent.\nUninstall reports one status per client so a missing earlier layer does\nnot hide a removed registration.\n\n---------\n\nCo-authored-by: Cursor Agent ", - "parents": ["b25922e4e8fe389cf17c151ccb7b4be4a42824d9"], - "authors": [ - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - }, - { - "name": "Cursor Agent", - "email": "cursoragent@cursor.com", - "user": { - "login": "cursoragent", - "__typename": "User" - } - } - ], - "pullRequests": [1504] - }, - { - "sha": "b4db35f092d7166aebdf4387b48f7652b1d1c3b6", - "subject": "fix: bind identity and coverage to the producing rule (#1513)", - "body": "fix: bind identity and coverage to the producing rule (#1513)\n\n* fix: bind identity and coverage to the producing rule\n\nLogical paths, container families, examined bytes, path-segment conventions, destination collisions, file-id leases, Mach-O CPU selection, and firmware cleanup now follow the observation that owns each rule.\n\n* fix: fail unmatched Mach-O slices and keep firmware roots independent\n\nA fat target whose architecture lipo did not list now stops before slice tools run. Chained fixups still count unread LC_DYLD_INFO rebase bytes, and a firmware cleanup failure no longer blocks the next workspace.\n\n* test: cover path identity and runtime families at the projection boundary\n\nNFC joins and segment conventions are now asserted by the path resolver, the Apple projection, and a real APK inventory instead of helper unit tests.\n\n* test: expect unread dyld rebase bytes in the Apple dispatch fixture\n\nThe legacy LC_DYLD_INFO fixture keeps a rebase range this reader does not decode, so the public CLI and MCP check now requires that partial coverage beside the bind opcodes.\n\n---------\n\nCo-authored-by: Cursor Agent ", - "parents": ["7a56fe6260cbda2e4c77e30d143db0e62f211b5b"], - "authors": [ - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - }, - { - "name": "Cursor Agent", - "email": "cursoragent@cursor.com", - "user": { - "login": "cursoragent", - "__typename": "User" - } - } - ], - "pullRequests": [1513] - }, - { - "sha": "46c9cba03a52b8ec382a686cd70ded6128225db8", - "subject": "fix(javascript): expand an escaped receiver's methods once (#1495) (#1517)", - "body": "fix(javascript): expand an escaped receiver's methods once (#1495) (#1517)\n\nSince #1471, escaping an object also escapes every method's results. Each\ncall through the object escapes it as the receiver, and each escape\nre-expanded all of its methods. N methods returning one shared object,\neach called once, did N times N work: 2,000 calls took 3.0 s of semantic\nanalysis and 4,000 took 12 s.\n\nExpansion below references depends only on syntax, so escapes now reuse\nit per expression and path. Identifiers that resolve to the same binding\nand path collapse to one, because the escape walk treats them alike.\nEvery escape site is still recorded. The semantic IR is byte-identical\non 50 sources, and the issue's case takes 253 ms at 2,000 and 638 ms at\n4,000.\n\nCloses #1495\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["b4db35f092d7166aebdf4387b48f7652b1d1c3b6"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1517] - }, - { - "sha": "f9ce32b4749026d3b6c05b8880f5549967cdb6ad", - "subject": "test(javascript): verify escaped receivers through CLI and MCP", - "body": "test(javascript): verify escaped receivers through CLI and MCP", - "parents": ["46c9cba03a52b8ec382a686cd70ded6128225db8"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1526] - }, - { - "sha": "72b3209f3a77b58a7dcd7096affb67ef71cf26c3", - "subject": "docs(website): explain autonomy and oracle lessons in Touhou reconstruction", - "body": "docs(website): explain autonomy and oracle lessons in Touhou reconstruction\n", - "parents": ["f9ce32b4749026d3b6c05b8880f5549967cdb6ad"], - "authors": [ - { - "name": "N0zoM1z0", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1532] - }, - { - "sha": "5fdb0636b4734cabfa3147e8fcc94976c3bd8aa4", - "subject": "fix(javascript): yield during per-file projection and graph construction (#1525)", - "body": "fix(javascript): yield during per-file projection and graph construction (#1525)\n\nanalyze_javascript_application ran several long phases with no event-loop\nturn, so MCP ping and cancellation waited: each file's parse, analysis and\nsemantic projection; building every application node and relationship\nbefore the application graph's first sealing step; and whole-graph schema\nparses inside both immutable graph factories.\n\n- Each file runs as steps (parse, static analysis, semantic analysis, then\n each projection pass), driven by the existing time-sliced checkpoint.\n- Application graph input construction yields between phases, per module\n link and per file of findings.\n- The pipeline transfers its privately built graph inputs to new sealing\n steps that validate the graph's own fields synchronously and elements,\n content checks and the digest in steps. The public copying factories\n keep their synchronous capture.\n\nResults are unchanged: graph IDs and the complete result digest match main\non five inputs including Obsidian's 23 MB obsidian.asar. On the issue's\n1,200-function fixture the longest event-loop block falls from about\n290 ms to 90 ms, and ping after abort from up to 286 ms to at most 56 ms.\nOn obsidian.asar it falls from 10.9 s to 5.4 s; the rest is one analyzer\nstage of a single very large file.\n\nRefs #1462\n\nCo-authored-by: Claude Opus 5.5 \nCo-authored-by: N0zoM1z0 <161784452+N0zoM1z0@users.noreply.github.com>", - "parents": ["72b3209f3a77b58a7dcd7096affb67ef71cf26c3"], - "authors": [ - { - "name": "Kaoru0822", - "email": "208281322+kaoru0822-kitauji@users.noreply.github.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - }, - { - "name": "N0zoM1z0", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1525] - }, - { - "sha": "92741187ecb77674bd9c1f6f6ad9ebb21b32bbf9", - "subject": "docs: list all supported clients in the REA skill (#1523)", - "body": "docs: list all supported clients in the REA skill (#1523)\n\ndocs: include all supported clients in the REA skill\n\nCo-authored-by: Ysopwnable <161784452+N0zoM1z0@users.noreply.github.com>", - "parents": ["5fdb0636b4734cabfa3147e8fcc94976c3bd8aa4"], - "authors": [ - { - "name": "Peter", - "email": "304086198+peter-research@users.noreply.github.com", - "user": { - "login": "peter-research", - "__typename": "User" - } - }, - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1523] - }, - { - "sha": "86b223b33ed3859df9b6d07527a58e800c739765", - "subject": "fix(setup): follow and validate Hermes sticky profiles (#1528)", - "body": "fix(setup): follow and validate Hermes sticky profiles (#1528)\n\n* fix: follow Hermes sticky profile for setup paths\n\n* test: cover Hermes sticky profile paths\n\n* fix: honor Hermes profiles with home overrides\n\n* style: format Hermes profile lookup\n\n* style: format Hermes profile tests\n\n* fix(ci): avoid load-sensitive escape regression timing\n\n* fix(setup): validate Hermes sticky profile identity\n\n---------\n\nCo-authored-by: N0zoM1z0 <1705004398@qq.com>", - "parents": ["92741187ecb77674bd9c1f6f6ad9ebb21b32bbf9"], - "authors": [ - { - "name": "Peter", - "email": "304086198+peter-research@users.noreply.github.com", - "user": { - "login": "peter-research", - "__typename": "User" - } - }, - { - "name": "N0zoM1z0", - "email": "1705004398@qq.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1528] - }, - { - "sha": "3059d8a40f6dcf1e0709937ed1be2166d704bbaf", - "subject": "test(clients): verify native DeepSeek Harness integration (#1524)", - "body": "test(clients): verify native DeepSeek Harness integration (#1524)\n\n* test(clients): verify native DeepSeek Harness integration\n\n* fix(ci): avoid load-sensitive escape regression timing", - "parents": ["86b223b33ed3859df9b6d07527a58e800c739765"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1524] - }, - { - "sha": "9964af6b79d7b8cf13858d6cc26176546a92c3fe", - "subject": "fix(ci): synchronize browser fixture events before inspection (#1534)", - "body": "fix(ci): synchronize browser fixture events before inspection (#1534)", - "parents": ["3059d8a40f6dcf1e0709937ed1be2166d704bbaf"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1534] - }, - { - "sha": "706bba6e13ed27faf34c79149aa4927938139dab", - "subject": "feat(process): report live capture progress through CLI and MCP", - "body": "feat(process): report live capture progress through CLI and MCP\n\nLong captures emitted only a final result, so a quiet child looked idle.\nPass the shared rate-limited progress reporter through the capture lifecycle\nand report the observed phase, elapsed time, and collected-unit counts.\nCLI writes those lines to stderr; MCP forwards them only when the client\nsupplied a progress token. Final Evidence on stdout keeps its shape.\n", - "parents": ["9964af6b79d7b8cf13858d6cc26176546a92c3fe"], - "authors": [ - { - "name": "Cursor Agent", - "email": "cursoragent@cursor.com", - "user": { - "login": "cursoragent", - "__typename": "User" - } - } - ], - "pullRequests": [1483] - }, - { - "sha": "6cd5ea0fb282c23cd08ca03e81ae2436b8c0661b", - "subject": "fix(process): coalesce delayed capture progress", - "body": "fix(process): coalesce delayed capture progress\n\nRetain one pending intermediate observation and drop stale live status before terminal cleanup. Preserve monotonic counts and final delivery while an observer is slow or rejects an update.\n\nVerify the send rate at its controlled-clock owner and lifecycle notification density at the CLI/MCP boundary, where receive timestamps include buffering and scheduling.\n", - "parents": ["706bba6e13ed27faf34c79149aa4927938139dab"], - "authors": [ - { - "name": "N0zoM1z0", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1483] - }, - { - "sha": "3cd80cbb88708229ad39105522ad2814e1c09c4b", - "subject": "test(process): prepare SDK validation before cancellation timing", - "body": "test(process): prepare SDK validation before cancellation timing\n", - "parents": ["6cd5ea0fb282c23cd08ca03e81ae2436b8c0661b"], - "authors": [ - { - "name": "N0zoM1z0", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1483] - }, - { - "sha": "bace2c5a4faf7ad55c574b181ed276693eaf84ae", - "subject": "fix(javascript): avoid argument limits when expanding escaped receivers", - "body": "fix(javascript): avoid argument limits when expanding escaped receivers", - "parents": ["3cd80cbb88708229ad39105522ad2814e1c09c4b"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1539] - }, - { - "sha": "b9c439831d709e2fe6b8c69b83ec4157dff43d99", - "subject": "test(clients): verify native Gemini CLI integration (#1541)", - "body": "test(clients): verify native Gemini CLI integration (#1541)", - "parents": ["bace2c5a4faf7ad55c574b181ed276693eaf84ae"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1541] - }, - { - "sha": "ca7ef69c0ceed367470cb2d8e867a33e61706b02", - "subject": "fix(javascript): yield inside semantic analysis and large projection passes (#1542)", - "body": "fix(javascript): yield inside semantic analysis and large projection passes (#1542)\n\n* fix(javascript): yield inside semantic analysis and large projection passes\n\nAfter #1525 the longest event-loop blocks were single stages on very large\nfiles: semantic analysis of Obsidian's 3.7 MB app.js ran 5.8 s in one piece,\nand its object projection 1.8 s.\n\n- analyzeParsedJavaScriptSemanticsSteps yields between the analysis phases\n and between the eight derived collectors; the synchronous function drains\n it, so results are unchanged.\n- Per-file analysis yields between open-receiver classification and static\n analysis and drives the semantic steps.\n- Semantic node creation, definitions and references, and the object and\n frontier passes yield every 64 items. Node creation keeps source order,\n which the per-file node budget depends on.\n\nOn obsidian.asar the longest block falls from 5,355 ms to 907 ms with the\nsame total time (40.6 s to 39.5 s). Graph IDs and complete result digests\nmatch main on five inputs. Remaining blocks up to about 0.9 s are single\nAST traversal passes inside the analyzers.\n\nRefs #1462\n\nCo-Authored-By: Claude Opus 5.5 \n\n* refactor(javascript): drop the unused synchronous derived-semantics wrapper\n\nCo-Authored-By: Claude Opus 5.5 \n\n---------\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["b9c439831d709e2fe6b8c69b83ec4157dff43d99"], - "authors": [ - { - "name": "Kaoru0822", - "email": "aisakamimaki@gmail.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1542] - }, - { - "sha": "1887e1120e91ee5f11672c2949c8b7ec59026c16", - "subject": "fix: reuse validators for identical output schemas", - "body": "fix: reuse validators for identical output schemas", - "parents": ["ca7ef69c0ceed367470cb2d8e867a33e61706b02"], - "authors": [ - { - "name": "Peter", - "email": "304086198+peter-research@users.noreply.github.com", - "user": { - "login": "peter-research", - "__typename": "User" - } - } - ], - "pullRequests": [1527] - }, - { - "sha": "aa7008f8a5937253f578a4338419c7e2330a9924", - "subject": "fix: reuse validators for identical output schemas", - "body": "fix: reuse validators for identical output schemas", - "parents": ["1887e1120e91ee5f11672c2949c8b7ec59026c16"], - "authors": [ - { - "name": "Peter", - "email": "304086198+peter-research@users.noreply.github.com", - "user": { - "login": "peter-research", - "__typename": "User" - } - } - ], - "pullRequests": [1527] - }, - { - "sha": "c73cf0ab7695049e5b8267f18182cb87200c78b2", - "subject": "fix(verification): reuse shared output schemas in Electron checks", - "body": "fix(verification): reuse shared output schemas in Electron checks\n", - "parents": ["aa7008f8a5937253f578a4338419c7e2330a9924"], - "authors": [ - { - "name": "N0zoM1z0", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1527] - }, - { - "sha": "539a0f95b5c0d43080cf0561bd5963d5ccf9548a", - "subject": "test(clients): verify native OpenCode integration (#1546)", - "body": "test(clients): verify native OpenCode integration (#1546)", - "parents": ["c73cf0ab7695049e5b8267f18182cb87200c78b2"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1546] - }, - { - "sha": "8c7569aca79349eec9def0fa98cbf04fdbcf0d02", - "subject": "test(clients): verify native Claude Code integration (#1549)", - "body": "test(clients): verify native Claude Code integration (#1549)", - "parents": ["539a0f95b5c0d43080cf0561bd5963d5ccf9548a"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1549] - }, - { - "sha": "5aa30b8b867836df578639e824d8b47bdc54f861", - "subject": "chore(website): simplify maintenance and detect documentation drift", - "body": "chore(website): simplify maintenance and detect documentation drift\n", - "parents": ["8c7569aca79349eec9def0fa98cbf04fdbcf0d02"], - "authors": [ - { - "name": "N0zoM1z0", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1547] - }, - { - "sha": "e964a06b83c92c03551d29c1b7ecfa7db322cce2", - "subject": "fix(website): preserve template-owned HTML formatting", - "body": "fix(website): preserve template-owned HTML formatting\n", - "parents": ["5aa30b8b867836df578639e824d8b47bdc54f861"], - "authors": [ - { - "name": "N0zoM1z0", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1547] - }, - { - "sha": "5d6eeb22fb3bc005163e3c680cf524ba7659b48a", - "subject": "fix(javascript): yield during the largest AST traversals (#1545)", - "body": "fix(javascript): yield during the largest AST traversals (#1545)\n\nAfter #1542 the longest event-loop blocks on large bundles were single AST\ntraversals inside one analyzer: member-mutation collection with its\nfixpoint, static source analysis, and function fingerprints, each about\none second on Obsidian's 3.7 MB app.js.\n\n- traverseJavaScriptAstSteps yields every 1,024 visited nodes with the\n same visit order; traverseJavaScriptAst drains it, so every existing\n caller is unchanged.\n- Member mutations, static analysis and fingerprints run as steps. The\n member-mutation fixpoint yields every 64 references, and fingerprints\n yield between callables.\n- The now-unused synchronous member-mutation and fingerprint wrappers are\n removed.\n\nGraph IDs and complete result digests match main on three inputs,\nincluding obsidian.asar. Over two runs there, the longest block falls\nfrom about 920 ms to 740 ms, the second from 860 to 595 ms, and blocks\nover 250 ms from 27 to 18, with total time within 1.5%.\n\nRefs #1462\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["e964a06b83c92c03551d29c1b7ecfa7db322cce2"], - "authors": [ - { - "name": "Kaoru0822", - "email": "aisakamimaki@gmail.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1545] - }, - { - "sha": "2d99e1e3b268181bb4b3e02e1cb769c550806481", - "subject": "test(ghidra): preserve Node heap options in adapter verification (#1550)", - "body": "test(ghidra): preserve Node heap options in adapter verification (#1550)", - "parents": ["5d6eeb22fb3bc005163e3c680cf524ba7659b48a"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1550] - }, - { - "sha": "47947eb01cfb5f15fb1d70042e35c02142436d25", - "subject": "perf(javascript): index returned object targets", - "body": "perf(javascript): index returned object targets", - "parents": ["2d99e1e3b268181bb4b3e02e1cb769c550806481"], - "authors": [ - { - "name": "Geekwolf", - "email": "geekwolf@163.com", - "user": { - "login": "geekwolf", - "__typename": "User" - } - } - ], - "pullRequests": [1537] - }, - { - "sha": "b973b1b1ec54d394643f2c842de04a22ed1c6780", - "subject": "test(javascript): cover returned object scaling", - "body": "test(javascript): cover returned object scaling", - "parents": ["47947eb01cfb5f15fb1d70042e35c02142436d25"], - "authors": [ - { - "name": "Geekwolf", - "email": "geekwolf@163.com", - "user": { - "login": "geekwolf", - "__typename": "User" - } - } - ], - "pullRequests": [1537] - }, - { - "sha": "9ffc6210a41b35b9ab8be878365ee7db29a83af9", - "subject": "test(javascript): remove duplicate escaped-receiver cases", - "body": "test(javascript): remove duplicate escaped-receiver cases\n", - "parents": ["b973b1b1ec54d394643f2c842de04a22ed1c6780"], - "authors": [ - { - "name": "N0zoM1z0", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1537] - }, - { - "sha": "a6d6e595f3eeb05c3347d1ad71ec7165b8a674a7", - "subject": "docs: add Italian (it) README translation (#1455)", - "body": "docs: add Italian (it) README translation (#1455)\n\n* docs: add Italian (it) README translation\n\nAdds README_it.md (full Italian translation of the English README) and updates the language nav bar in all existing READMEs to include the new [Italiano] link, appended at the end of the bar (after Bahasa Indonesia) to match the repository's convention for adding new languages.\n\nRebuilt on top of current main to resolve the merge conflict caused by the recently added Bahasa Indonesia (README_id.md) translation.\n\nCloses #1453\n\n* docs: fix Italian README showcase anchors\n\n---------\n\nCo-authored-by: morluto <76467478+morluto@users.noreply.github.com>", - "parents": ["9ffc6210a41b35b9ab8be878365ee7db29a83af9"], - "authors": [ - { - "name": "Franky100-pig", - "email": "fufranky971@gmail.com", - "user": { - "login": "Franky100-pig", - "__typename": "User" - } - }, - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - } - ], - "pullRequests": [1455] - }, - { - "sha": "961471205cd0199f28c27bd91e5e7f0608f0bdb4", - "subject": "fix(docs): format Italian README tables", - "body": "fix(docs): format Italian README tables\n", - "parents": ["a6d6e595f3eeb05c3347d1ad71ec7165b8a674a7"], - "authors": [ - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - } - ], - "pullRequests": [] - }, - { - "sha": "02ef2b1c41e80364b6482e4586ae40e575c6d5a5", - "subject": "docs(zh): rename title to ้€†ๅ‘ไธ€ๅˆ‡", - "body": "docs(zh): rename title to ้€†ๅ‘ไธ€ๅˆ‡\n", - "parents": ["961471205cd0199f28c27bd91e5e7f0608f0bdb4"], - "authors": [ - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - } - ], - "pullRequests": [] - }, - { - "sha": "c8fd2f152b7e757a1b41ce9f5df20cd91d41462e", - "subject": "fix(apple): scope keyed archive traversal to the selection", - "body": "fix(apple): scope keyed archive traversal to the selection\n\nSigned-off-by: Rudy Celekli <47457359+rudycelekli@users.noreply.github.com>\n", - "parents": ["02ef2b1c41e80364b6482e4586ae40e575c6d5a5"], - "authors": [ - { - "name": "Rudy Celekli", - "email": "47457359+rudycelekli@users.noreply.github.com", - "user": { - "login": "rudycelekli", - "__typename": "User" - } - } - ], - "pullRequests": [1378] - }, - { - "sha": "4b985e5021f578e6ef0bc2a412abe9cba6bdaca1", - "subject": "fix(artifacts): take nested container families from bytes (#1553)", - "body": "fix(artifacts): take nested container families from bytes (#1553)\n\nInventory gave nested members a ZIP or ASAR family from their path\nsuffix. Byte classification replaced it only for ZIP magic, so text named\n`.apk` or `.asar` stayed a container, and encrypted entries and symlinks\nkept the suffix guess. A filesystem `.asar` without an ASAR header failed\nthe whole inventory as a malformed archive.\n\nNested ZIP families now follow ZIP magic and ASAR follows its header\npickle, shared with root classification. An unread member named like a\ncontainer has an unknown format and a limitation naming the suffix. ASAR\nexpansion requires the header.\n\nThe Android projection adds a limitation when no root AndroidManifest.xml\nwas observed, and its rejection names the observed root format.\n\nFixes #1491\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["c8fd2f152b7e757a1b41ce9f5df20cd91d41462e"], - "authors": [ - { - "name": "Kaoru0822", - "email": "aisakamimaki@gmail.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1553] - }, - { - "sha": "66a9ad58fc53e80150abe6d27bd8bba516541f8b", - "subject": "test(clients): verify native GitHub Copilot CLI integration (#1555)", - "body": "test(clients): verify native GitHub Copilot CLI integration (#1555)", - "parents": ["4b985e5021f578e6ef0bc2a412abe9cba6bdaca1"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1555] - }, - { - "sha": "0e19db9fce74af2081144102f5787cf90a450244", - "subject": "fix(javascript): unify package resolution and resolve exact exports subpaths (#1424)", - "body": "fix(javascript): unify package resolution and resolve exact exports subpaths (#1424)\n\n* fix(javascript): resolve exact package export subpaths\n\nBare module specifiers with subpaths now resolve against the selected\npackage's exports map instead of staying external. An exact subpath key\nselects its target through the existing condition, array, and null\nsemantics, and the selected target resolves as one exact file with no\nextension or index fallback. A declared exports map encapsulates every\nother subpath lookup, and packages without an exports map keep legacy\nfile and directory-index resolution.\n\nPackage-private import aliases remain external pending a separate\nincrement (#1365).\n\nVerification: npm run check:fast; focused and full\nsrc/application/javascript source tests on Windows;\nverify:test-discovery; docs:check. Four pre-existing failures in\nJavaScriptFileUrlPaths and JavaScriptModuleSpecifierPaths reproduce on\nunmodified main on Windows because their fixtures write file names\ncontaining '?'.\n\n* fix(javascript): unify package path resolution\n\n---------\n\nCo-authored-by: morluto <76467478+morluto@users.noreply.github.com>", - "parents": ["66a9ad58fc53e80150abe6d27bd8bba516541f8b"], - "authors": [ - { - "name": "AWUQAQ", - "email": "clw25952@gmail.com", - "user": { - "login": "AWUQAQ", - "__typename": "User" - } - }, - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - } - ], - "pullRequests": [1424] - }, - { - "sha": "b32a11e1a7a1148bd8a2964cb197925ee9f9fb46", - "subject": "docs: correct host requirements in the README analysis tables (#1422)", - "body": "docs: correct host requirements in the README analysis tables (#1422)\n\n- EVM bytecode and recorded crashes: state the Linux x64 host requirement.\n `EvmoleInterfaceProvider` and `PwntoolsDecoder` refuse every other host\n with `capability_unavailable`, but only the neighbouring offline ELF layout\n row said so.\n- Translations: Android analysis has supported Windows x64 since 6.2.0\n (#1276), which updated only the English table; 16 translations still said\n Linux/macOS.\n\nTranslated cells reuse each README's own wording: the recorded-crash cell\ncopies that file's ELF-row pwntools phrase, and the EVM and Android cells\nfollow the construction the same table already uses for host platforms.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["0e19db9fce74af2081144102f5787cf90a450244"], - "authors": [ - { - "name": "Fazmin Nizam", - "email": "fazmin.nizam@gmail.com", - "user": { - "login": "Fazmin", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1422] - }, - { - "sha": "944981d8d55e6ce2369362058e3325b267cbbe2e", - "subject": "docs: correct stale logging, Ghidra host, and example path statements (#1420)", - "body": "docs: correct stale logging, Ghidra host, and example path statements (#1420)\n\n- CONTRIBUTING: CLI logs go to stderr, not stdout. `createLogger` writes every\n mode to fd 2 so protocol and `--json` stdout stay parseable.\n- Get started: Ghidra supports Linux arm64 (`GhidraInstallation` maps\n `linux.arm64`), as installation.md already states.\n- Browser guide: drop the caption claiming the hosted request path carries a\n `/rea/` prefix. The guide now targets rea.tools, where the example is served\n at `/examples/notes-web/`, as the evidence table above it shows.\n- JavaScript workflows: six CLI commands accept inline JSON or a JSON file,\n not five; `inspect-analysis-view` was added after the sentence was written.\n\nCo-authored-by: Claude Opus 5.5 \nCo-authored-by: morluto <76467478+morluto@users.noreply.github.com>", - "parents": ["b32a11e1a7a1148bd8a2964cb197925ee9f9fb46"], - "authors": [ - { - "name": "Fazmin Nizam", - "email": "fazmin.nizam@gmail.com", - "user": { - "login": "Fazmin", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - }, - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - } - ], - "pullRequests": [1420] - }, - { - "sha": "afdaf981171213b8f7e739ded685e8e805a8e842", - "subject": "fix(hopper): treat a directory launcher path as missing (#1426)", - "body": "fix(hopper): treat a directory launcher path as missing (#1426)\n\n`HOPPER_LAUNCHER_PATH` availability was decided by an `X_OK` access check\nalone, which a searchable directory also passes. Pointing it at the\n`Hopper Disassembler.app` bundle instead of its launcher made `rea providers`\nreport Hopper as available and `rea doctor` report it healthy, while analysis\nthen failed with an unrelated `version_unresolved` rejection.\n\nRequire a regular file in both the provider availability probe and the\ndoctor executable probe, matching the Ghidra launcher check. A directory now\nreports `executable_missing`, and doctor reports `config_drift` with its\nexisting HOPPER_LAUNCHER_PATH remediation.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["944981d8d55e6ce2369362058e3325b267cbbe2e"], - "authors": [ - { - "name": "Fazmin Nizam", - "email": "fazmin.nizam@gmail.com", - "user": { - "login": "Fazmin", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1426] - }, - { - "sha": "2ec93ba1662ff0d61496d4d10337ae43ca03ccdf", - "subject": "docs: celebrate 60,000 GitHub stars ๐ŸŽ‰ (#1559)", - "body": "docs: celebrate 60,000 GitHub stars ๐ŸŽ‰ (#1559)\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["afdaf981171213b8f7e739ded685e8e805a8e842"], - "authors": [ - { - "name": "Kaoru0822", - "email": "aisakamimaki@gmail.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1559] - }, - { - "sha": "24d93376492d167fe7d96f6c10dee071b9ef363f", - "subject": "fix(native): preserve compact reference provenance (#1438)", - "body": "fix(native): preserve compact reference provenance (#1438)\n\nCo-authored-by: N0zoM1z0 <161784452+N0zoM1z0@users.noreply.github.com>", - "parents": ["2ec93ba1662ff0d61496d4d10337ae43ca03ccdf"], - "authors": [ - { - "name": "Joseph Demarest", - "email": "79677753+JosephDemarest@users.noreply.github.com", - "user": { - "login": "JosephDemarest", - "__typename": "User" - } - }, - { - "name": "N0zoM1z0", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1438] - }, - { - "sha": "de619bd33450a9869395eaeb25fe5c4d6e034e36", - "subject": "fix(ida): canonicalize the headless workspace root before opening (#1481)", - "body": "fix(ida): canonicalize the headless workspace root before opening (#1481)\n\nOn macOS the default workspace root is os.tmpdir() under /var/folders,\nand /var is a symlink to /private/var. idalib-mcp reports the canonical\ninput path from idb_open/idb_list, while REA compared it against the\nuncanonicalized private copy with normalize(), so every headless IDA\nanalysis failed its identity check (surfacing as unreadable_output) and\nthe spawned idalib worker was never released.\n\nResolve the workspace root with realpath() when allocating the private\nworkspace so the input path REA sends already matches what upstream\nreports.\n\nCo-authored-by: Xingchuan Ma \nCo-authored-by: Claude Opus 5.5 ", - "parents": ["24d93376492d167fe7d96f6c10dee071b9ef363f"], - "authors": [ - { - "name": "Max", - "email": "68940212+AS9929@users.noreply.github.com", - "user": { - "login": "AS9929", - "__typename": "User" - } - }, - { - "name": "Xingchuan Ma", - "email": "xingchuan.ma@msn.com", - "user": null - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1481] - }, - { - "sha": "8c47a9ce4b1349b3ccd50da8f8c587a3080759af", - "subject": "fix(javascript): yield during receiver and reference classification (#1557)", - "body": "fix(javascript): yield during receiver and reference classification (#1557)", - "parents": ["de619bd33450a9869395eaeb25fe5c4d6e034e36"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1557] - }, - { - "sha": "a929c9f714f5f27d3232bee83a162fa21d5dc449", - "subject": "fix(mobile): bound framework conventions to path segments (#1506)", - "body": "fix(mobile): bound framework conventions to path segments (#1506)\n\nCo-authored-by: morluto <76467478+morluto@users.noreply.github.com>", - "parents": ["8c47a9ce4b1349b3ccd50da8f8c587a3080759af"], - "authors": [ - { - "name": "Thang Luu", - "email": "thangldw@gmail.com", - "user": { - "login": "thangldw", - "__typename": "User" - } - }, - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - } - ], - "pullRequests": [1506] - }, - { - "sha": "2d426c924c536cf6d905b992a9e334ee51f3f28f", - "subject": "fix(native): format runtime convention guard", - "body": "fix(native): format runtime convention guard\n", - "parents": ["a929c9f714f5f27d3232bee83a162fa21d5dc449"], - "authors": [ - { - "name": "morluto", - "email": "76467478+morluto@users.noreply.github.com", - "user": { - "login": "morluto", - "__typename": "User" - } - } - ], - "pullRequests": [] - }, - { - "sha": "a53689c55d6e801d78596a36173fa2fee80be918", - "subject": "fix(mcp): stop advertising complete Evidence in input examples (#1560)", - "body": "fix(mcp): stop advertising complete Evidence in input examples (#1560)\n\nHosts forward every tool's input schema to the model on each request.\nSeventeen tools advertised a canonical example that embedded a complete\nproducer Evidence record, up to 22 KB each, accounting for 116 KB of the\n450 KB of advertised input schemas.\n\nAdvertised examples now show an embedded Evidence record as its exact\nretained-evidence reference when the canonical input accepts one, and\nomit an example that can only carry inline Evidence. Canonical contract\nexamples, their executable tests, and validation are unchanged.\n\nCo-authored-by: Claude Opus 5.5 ", - "parents": ["2d426c924c536cf6d905b992a9e334ee51f3f28f"], - "authors": [ - { - "name": "Kaoru0822", - "email": "aisakamimaki@gmail.com", - "user": { - "login": "kaoru0822-kitauji", - "__typename": "User" - } - }, - { - "name": "Claude Opus 5.5", - "email": "noreply@anthropic.com", - "user": { - "login": "claude", - "__typename": "User" - } - } - ], - "pullRequests": [1560] - }, - { - "sha": "e4cc0f09de257aad27a8d8b8e8512fbe1ef2d960", - "subject": "fix(setup): reject invalid OMP profiles before fallback writes (#1562)", - "body": "fix(setup): reject invalid OMP profiles before fallback writes (#1562)", - "parents": ["a53689c55d6e801d78596a36173fa2fee80be918"], - "authors": [ - { - "name": "Ysopwnable", - "email": "161784452+N0zoM1z0@users.noreply.github.com", - "user": { - "login": "N0zoM1z0", - "__typename": "User" - } - } - ], - "pullRequests": [1562] - }, - { - "sha": "649661dc8baa6976bbd8385c65ef0f21aa5745de", - "subject": "fix(javascript): stop reading media preload attributes as Electron preloads", - "body": "fix(javascript): stop reading media preload attributes as Electron preloads\n\nHTML audio and video elements have their own `preload` attribute (\"none\",\n\"metadata\", \"auto\"). A React renderer compiles `