595 Commits
Author SHA1 Message Date
Haseeb Heaven faa9c7b0b1 docs: reposition RE-Agent around serious legacy maintenance and verifiable porting (#33)
* docs: reframe README.md around verifiable legacy preservation

* docs: reframe docs/index.md around verifiable legacy preservation

* docs: define professional legacy case study evidence standard

* docs: link case-study standard and stable repository evidence

* placeholder

* test(evidence): add run-bound case study validator

* test(evidence): verify manifest binding, captures and malformed submissions

* ci: verify real case-study evidence contracts

* docs: scope GPL legacy music player as unverified real application target

* fix(evidence): recompute exact PASS outcomes and reject symlink ancestor traversal

* test(evidence): detect false PASS and unsupported comparison semantics
2026-10-15 17:15:25 +05:30
heaven-hm d7798e91f1 Merge branch 'main' into develop 2026-10-15 16:08:50 +05:30
heaven-hm 25237bf8da feat(scripts): compare Ghidra and radare2 function inventories 2026-10-15 16:07:53 +05:30
heaven-hm 8ab7cb3c8c Merge branch 'feat/rea-engine-evidence-audit-20261014' into HEAD
# Conflicts:
#	README.md
#	THIRD_PARTY_NOTICES.md
#	benchmarks/native-windows-ports/snake/README.md
#	benchmarks/native-windows-ports/snake/manifest.json
#	package.json
2026-10-15 15:44:20 +05:30
heaven-hm a33b10e2cf feat!: adopt RE-Agent identity and legacy maintenance purpose 2026-10-15 10:25:38 +05:30
heaven-hm 9134b3c007 feat(maintenance): add modular legacy skills and read-only snapshot analysis 2026-10-15 10:25:11 +05:30
heaven-hm 85fc7c58d1 feat: strengthen reconstruction and runtime workflows 2026-10-14 23:58:57 +05:30
heaven-hm 70ac34d6b6 feat: add game frame comparison and tool packaging 2026-10-14 23:58:45 +05:30
heaven-hm fac02920f6 fix(benchmarks): drain cancellation owners through in-process stages 2026-10-13 23:14:23 +05:30
heaven-hm 25e78a99eb fix(benchmarks): create missing output parents on fresh clones 2026-10-13 23:01:38 +05:30
heaven-hm 0d61a27595 fix(recovery): allow installer retries and preserve concurrent stop requests 2026-10-13 22:56:56 +05:30
heaven-hm 722f26f6f8 feat(identity): package rea-engine with host-agent workflow and fork release controls 2026-10-13 22:46:19 +05:30
heaven-hm 04d9246cdf feat(benchmarks): reconstruct and compare real managed software and game binaries 2026-10-13 22:45:41 +05:30
heaven-hm 110dcd493b feat(tools): bundle verified ILSpy and X11 graphics dependencies 2026-10-13 22:45:32 +05:30
Haseeb Mir f79f1b06d8 Merge remote-tracking branch 'heaven/main' into feat/autonomous-reconstruction 2026-10-13 18:15:59 +05:30
8823c55b0c feat(ghidra): decode Swift String literals in function dossiers (#2049)
* feat(ghidra): decode Swift String literals in function dossiers

Swift passes a String as two words. Small literals keep their UTF-8 bytes
inside those words, and immortal large literals keep a count plus a pointer
to their bytes biased by 32. Ghidra creates no data reference for either, so
analyze_function reported no strings for Swift code.

On AArch64 programs that contain Swift metadata, the Ghidra bridge now runs
constant propagation over the function and decodes register pairs where
Swift consumes a String: consecutive argument registers at calls and tail
calls, x0 and x1 at returns, and both registers of one STP. Large literals
must resolve to terminated bytes inside one initialized block that is not
executable. A pair whose registers both come from conditional selects is
skipped, because Ghidra forks each select without correlating the
condition and could otherwise pair words from different cases.

Decoded values are a derivation from the ABI layout rather than observed
references, so they appear in a new optional swift_string_literals field
with their source instruction, registers and raw words, and in a matching
inspect_analysis_view facet. referenced_strings is unchanged.

Refs #2030

* fix(ghidra): bound Swift literal reads and compare decoded strings

Large immortal literals are measured against the remaining heap before
allocation, and a failed fit stays visible as a limitation. The canonical
empty string is kept. Small and large literals now require matching
address nullability, and function comparison treats decoded literals as
string evidence without equating a missing record to an empty one.

* fix(ghidra): budget Swift literal decoding and tighten use sites

Large literals now draw on one heap budget per dossier, measured once
before decoding, instead of a separate check per literal. A literal that
does not fit is listed in a new swift_string_literal_omissions field
with its address, byte length and reason, so consumers read omissions
from structured data rather than from limitation text.

strings_names comparison checks referenced strings and names first and
reports a change there even when Swift literal coverage differs; it
returns unknown only when those facts match and literal coverage is
absent on one side or partial.

A computed jump counts as a tail call only when it has no resolved
target inside the function, so jump tables no longer qualify, and a
return requires a RETURN p-code operation, so traps no longer qualify.

Decoded literals keep control characters, which Swift strings may
contain and JSON escapes. The Swift verifier builds the literal fixture
for arm64 on any Mac host and now also covers the empty string and a
literal containing a tab.

* fix(ghidra): charge escaped JSON and follow copied selects

The Swift literal budget now charges the worst case per UTF-8 byte: UTF-16
text, six escaped JSON characters held in Gson's growing buffer and in the
returned String, and the UTF-8 bytes written to the socket. Literals made
of control characters can no longer exceed the reserved heap.

A jump counts as a tail call only when every resolved target lies outside
the function. The conditional select check follows register copies back
to their definition, so selects copied into argument registers are
recognized like selects written there directly.

strings_names reports a change when both dossiers decoded different
literals at the same use site, even when either side has omissions; it
returns unknown only when no such use site disagrees.

* fix(ghidra): bound literal records and trace selects across branches

Every Swift literal record now pays a fixed cost against the dossier
budget in addition to its text, so many empty or small literals are
bounded as well. The first record that does not fit is kept as an
omission and decoding stops there, which keeps the omission record
itself bounded; omissions now describe small or large literals.

The conditional select check searches every predecessor path for the
reaching definitions, following register copies, so selects made
before a branch into the use block are recognized.

A dossier records Swift literals and their omissions together. Coverage
reads omissions first, and strings_names compares every use site that
neither side omitted: a decoded literal is known where it was recorded,
and an absence is known only in a dossier whose decoding examined every
use site.

* fix(ghidra): stop every flow at the literal budget and route omissions

Ending one flow from the evaluator leaves other queued flows running, so
the budget now records a shared stop that every flow checks before it
examines another instruction. A record that exceeds the budget is routed
by that capacity result rather than by whether text was decoded, so a
small literal over budget becomes an omission instead of a literal.

When coverage is partial, the per site comparison keeps each literal's
representation as well as its value, matching the full strings_names
projection.

* fix(ghidra): keep unresolved Swift tail-call sites unknown

---------

Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: morluto <[email protected]>
2026-10-13 20:41:10 +08:00
Ysopwnable 2f3dee3fcf test(javascript): verify Windows path case and load scope (#2635)
Select the Windows curated lane for edits to the shared runtime path matcher and its workflow suite. Strengthen the existing POSIX/Windows mapping controls with matching basis, coherent target/script coordinates, caller spelling and static load-state assertions.

Follow-up to #2422; thanks to @Aurantium-47 for identifying the recorded-path grammar issue.

Verified with actual Windows 11 x64, official Node 24.18.0 and production CLI/MCP workflows using published npm 11.16.0 module Evidence. Four exact/mismatched implicit/explicit mapping cases pass with unchanged normalized hashes. The capture provider was Node Inspector; no IDA, Ghidra or Electron GUI verification is claimed.

230 focused tests, all eight CI static tasks, architecture guards and documentation checks pass after rebasing onto main fb28ec153. The unrelated release-checkpoint and dyld fixture corrections were integrated from upstream; no patches to those files are included here. Final Windows MCP replay at e6e86946d preserves all four normalized hashes, with no owned Node processes remaining. Resource probes ran serially at BelowNormal priority with one CPU and 512 MiB Node heaps; calls took 251–620 ms and the sampled process-family working-set sum peaked at 499,380,224 bytes. Source pins, provenance and measurement limits are recorded in experiments/analysis-efficiency/windows-posix-reconciliation.md.

All 34 jobs in current-head CI run 38391921571 passed, including the Windows capability/package lane, all six portable test shards, JavaScript recovery and the required aggregate. Current-head Codex and Greptile reviews are clean; both prior scope-selection findings were fixed and resolved.
2026-10-13 20:37:48 +08:00
Shreyansh Jainandmorluto a8b50ea147 refactor(firmware): split verification into staged functions (#2713)
Refactor firmware verifier into staged functions

Restructure scripts/verify/firmware/analysis.mjs for readability without changing behavior.

- Move prerequisite checks into checkPrerequisites()
- Split the main flow into stageCli, stageMcp, stageExt4 and stageGhidra
- Extract timeouts and size limits into named constants
- Rename cli/call helpers to runCli/callTool

Checks, order of operations, error messages and env vars are unchanged.

Co-authored-by: morluto <[email protected]>
2026-10-13 20:25:58 +08:00
Haseeb Mir 034a90c762 fix(runtime): retain the referenced LGPL notice from SPDX 2026-10-13 17:44:25 +05:30
Haseeb Mir b9032a1369 merge: preserve latest upstream REA capabilities 2026-10-13 17:37:55 +05:30
Haseeb Mir f5d142773b docs(autonomy): package agent workflows and scoped verification reports 2026-10-13 17:33:07 +05:30
Haseeb Mir 194aee4766 feat(benchmark): add native Calculator reconstruction and visual checks 2026-10-13 17:32:50 +05:30
Haseeb Mir 62ddbf724f feat(runtime): trace owned functions with verified Frida preload 2026-10-13 17:30:59 +05:30
Haseeb Mir fb7f32e66c feat(packaging): create pinned offline tool bundles with notices 2026-10-13 17:30:24 +05:30
Haseeb Mir 567b642254 feat(tools): discover and bootstrap verified analysis engines 2026-10-13 17:30:05 +05:30
Haseeb Mir 42437ba908 feat(verification): recover and prove bounded affine behavior 2026-10-13 17:29:40 +05:30
morluto fa0a9b2d32 ci: observe affected-owner test plans against full results 2026-10-13 19:21:09 +08:00
morluto c8d861f976 ci: scope timing helpers to portable verification 2026-10-13 19:12:26 +08:00
morluto bd2c202dd9 fix(ci): reject incomplete verification plans 2026-10-13 19:06:31 +08:00
morluto f0f09950f3 ci: finish main validation and balance complete test costs 2026-10-13 18:54:05 +08:00
morluto 3af8f847f0 ci: fix PR metadata triggers and defer expensive runner work 2026-10-13 18:38:46 +08:00
记得吃中饭 2995ec6910 fix(ghidra): resolve file offsets in decompile (#2101)
* fix(native): expose loaded image bases in overviews

* test(ghidra): retain resources when verifier cleanup fails

* docs(ghidra): spell out file-offset address mapping

* fix(ci): separate and retry NativeAOT dependency restoration

* fix(test): resolve CI script file URLs on Windows

* fix(native): retain conflict observations and actionable CLI guidance

* fix(fixtures): keep NativeAOT retry logs credential-safe

* fix(fixtures): redact authenticated URLs at diagnostic creation

* fix(ghidra): restrict source-coordinate observations to decompilation

* fix(cli): identify conflicting file-offset selectors accurately

* fix(ghidra): bind file offsets to admitted target sources

* fix(ghidra): preserve resolved file-offset failure context

* test(ghidra): verify ELF address and file-offset round trips

* test(nativeaot): align diagnostic regressions with fixture host support
2026-10-13 18:23:17 +08:00
N0zoM1z0 8583a190c0 fix(website): keep omitted language selectors free of whitespace
Indent the optional language selector with its value so a nonindexable draft does not generate a line containing only spaces. Indexed-page markup is unchanged.

Validation: website.py check passes all 12 maintenance regressions; synchronization changes only the draft header blank line.
2026-10-13 18:21:09 +08:00
morluto ab02f3c8d6 ci: reduce reporter fan-out and preserve shard history 2026-10-13 18:16:10 +08:00
morluto d13c9f840d ci: reduce redundant compatibility and qualification work
Select SQLite compatibility by explicit source, fixture, lifecycle, and script ownership while retaining every version in full qualification. Share the canonical scope inventory between planning and the required gate.

Reuse recent exact-SHA full qualification only for hourly schedules, with trusted successful-run metadata and receipts. Force a daily refresh, reject stale original runs even after retries, and never renew proof from reused validation.

Report attempt-specific queue, execution, and matched step timing in a separate completion workflow using trusted default-branch code and read-only API access. Preserve raw metadata and unknown timings without delaying validation or publication.

Validation: 177 focused tests; typecheck/lint; knip; actionlint 1.7.7; all 1046 tests discovered; live 37-job API report smoke. Remote workflow scheduling and real-provider matrices remain CI verification.
2026-10-13 17:46:04 +08:00
morluto 0c7f4dfbd9 ci: separate fast feedback from full qualification
Scope main pushes from a successful ancestor so canceled runs cannot hide changes. Keep the complete portable suite in fast feedback and move coverage plus Intel macOS to hourly, manual, explicit-full, and release qualification. Let qualification finish independently of superseded feedback.

Bind publication to full qualification at its exact revision and publish the verified tarball after checking workflow identity, version, and SHA-256. Keep trusted cache writers and reject incomplete merged test inventories.

Validation: 151 focused CI tests; typecheck/lint; actionlint 1.7.7; knip; all 1044 files discovered; bounded blob/merge smoke; macOS package verifier with retention and cleanup; npm pack dry run. Native Linux/ARM/Windows and remote workflow execution remain CI verification.
2026-10-13 17:09:53 +08:00
Olorin 4276aaf18b feat(signals): discover installed decoders and option help (#2487)
* feat(signals): discover installed decoders and selected option help

* fix(signals): bound retained discovery data and preserve resource failures

* fix(signals): complete CLI help and portable decoder patterns

* test(signals): verify case-insensitive decoder help queries

* fix(signals): retain discovery operation across cleanup retries
2026-10-13 15:58:19 +09:00
OlorinandN0zoM1z0 9c34c091b3 feat(captures): discover installed protocol and field definitions (#2496)
* feat(captures): discover installed protocol and field definitions

* test(captures): isolate the direct glossary oracle profile

* test(captures): accept padded kernel limit reports

* fix(captures): detach every retained glossary column

* fix(captures): describe every field discovery CLI option

* fix(captures): retain discovery operation across cleanup retries

---------

Co-authored-by: N0zoM1z0 <[email protected]>
2026-10-13 15:55:25 +09:00
chAngEandchAngE 68ecf3df8c fix(browser): exclude sensitive binary lengths from historical captures (#2477)
Co-authored-by: chAngE <[email protected]>
2026-10-13 14:49:47 +08:00
Stefano RizzelloandClaude Opus 5 ab62ee9dcf fix(windows): preserve caller affinity only within one processor group (#2202)
* fix(windows): preserve caller affinity only within one processor group

`spawnProcess` read the caller's affinity mask and applied it to the
suspended child unconditionally. A mask names processors relative to one
processor group, and Windows assigns each new process to a group of its
own choosing, so on hosts with more than 64 logical processors the child
is often placed in another group. `SetProcessAffinityMask` then rejects
the mask with ERROR_INVALID_PARAMETER (87) and the spawn fails, making
every owned provider process start intermittently on such hosts.

Affinity is a nicety, not an authority or isolation control, so it is now
applied only when the caller and the suspended child both occupy the same
single processor group. A child placed in another group keeps that group's
default affinity and the spawn proceeds. Job Object membership,
kill-on-owner-close policy, owner normalization and priority preservation
are unchanged, and the mask failure remains fatal within a shared group,
where it is not expected.

Single-group hosts, including every host with 64 or fewer logical
processors, are unaffected: `GetProcessGroupAffinity` reports one group
for both processes and the same mask is applied as before.

The optional process-boundary fixture gains an `affinity` observation,
and the native verification lane asserts that an owned spawn succeeds and
that the child's mask matches the caller's whenever both share a single
group.

Fixes #2181

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

* fix(windows): refuse to widen a pinned caller's affinity across groups

Addresses review feedback on the first commit.

An unconstrained caller loses nothing when Windows places an owned child
in another processor group, so that spawn proceeds with the group's
default. A caller deliberately pinned to fewer processors than its group
holds is a different case: silently accepting the default would hand the
provider tree the whole group, which `docs/installation.md` tells
operators to rely on affinity to prevent. Such a spawn now fails naming
the constraint instead. `GetProcessAffinityMask` already reports the
group's active set, which distinguishes the two without another query.

Selecting the caller's group at creation through
PROC_THREAD_ATTRIBUTE_GROUP_AFFINITY was tried first and rejected:
`CreateProcessW` fails with ERROR_INVALID_PARAMETER on a host with a
single processor group, both alongside PROC_THREAD_ATTRIBUTE_JOB_LIST and
on its own, so it cannot carry the ordinary path.

The boundary fixture's affinity observation now reports a process id's
own mask rather than its own, because a separate probe process is
assigned its own group and cannot stand in for the process that spawns
the child. Masks and the group's active set cross as fixed-width
hexadecimal strings: a mask can set bits above the safe-integer range,
where `JSON.parse` would round two different masks to one value.

The verification lane asserts the mask is inherited exactly when caller
and child share a group, and otherwise that the caller was unconstrained.

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

* docs(windows): record what owned-process affinity does not preserve

A mask covering its group's whole active set does not distinguish a
caller the system placed in that group from one that selected the group
deliberately, so an owned child can still be placed elsewhere with its
processor count bounded and its group placement lost. Treating that case
as constrained instead is not available: on a multi-group host an
ordinary process is assigned a group by the system and its mask is that
group's active set, so refusing it would fail every owned spawn there.

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

---------

Co-authored-by: Claude Opus 5 <[email protected]>
2026-10-13 14:49:34 +08:00
YsopwnableandLuis Taffelli 141d2095f5 test(hopper): repair Linux demo setup and native verification (#2638)
* fix(verification): align Linux Hopper setup lane with current contracts

* fix(verification): retain orphan checks on clean Linux runners

* fix(verification): detect Hopper through alternate launcher paths

* fix(verification): report identified Hopper leaks before proc errors

* fix(verification): distinguish Hopper string recognition from byte fidelity

* fix(verification): report full literal decoding coverage explicitly

---------

Co-authored-by: Luis Taffelli <[email protected]>
2026-10-13 14:39:18 +08:00
Ysopwnable c105391db5 fix(hopper): stop Linux demo children when the REA owner exits (#2499)
Bind the owned demo helper to REA's private stdin stream and unwind child
cleanup on EOF during startup or analysis. Verify graceful and SIGKILL owner
exit through real CLI/MCP workflows and preserve unrelated processes.

Assisted-by: Reimu (gensokyo-skills:reimu-incident-triage)
2026-10-13 12:59:22 +08:00
Quentin LimoandN0zoM1z0 9581e067ad feat(pcap): add bounded capture summaries through CLI and MCP
Summarize saved Wireshark4.x captures with enforced native resource limits, serialized admission, stable snapshot verification and retained fact/text pages. Preserve complete inventories within resource budgets and source uncertainty; report cleanup failure with partial Evidence and retained ownership.

Verified six recorded corpora /13026 packets with independent Scapy/Python oracles, real CLI/MCP/schema parity,60 SNI names,132 DNS addresses and1000 URIs. Real TShark CI now exercises summary/paging. Actual Windows/Bun Wireshark remains unverified; macOS capture requires a separate enforceable-bound decision.

Co-authored-by: 3QL <[email protected]>
Co-authored-by: N0zoM1z0 <[email protected]>
2026-10-13 04:53:03 +00:00
Ysopwnable fa4b828865 fix(cli): normalize empty Windows profile before imports (#2482)
Follow-up to #2345; thanks to @gefrezim for the import-time home lookup diagnosis.

Normalize only an empty Windows USERPROFILE before runtime dependency imports, preserving all nonempty caller selections. Reuse the existing public setup dry-run regression in the Windows curated CI lane. No additional filesystem query, engine call, cache or retry.

Verified real Windows Node 24.18.0 CLI unset/empty/selected-profile controls, setup dry-run home selection and unchanged configuration, and baseline/candidate SDK stdio MCP catalogue parity. Nine related tests and static/docs checks passed. No IDA or Ghidra engine was used. Scoped resource observations and measurement limits are recorded in experiments/analysis-efficiency/windows-empty-profile.md.

Fixed the review finding and original CI package-scope ownership failure. Current-head CI is green; the unrelated MCP identity timeout passed on a failed-job rerun without changing its code or timeout. Current-head review completed with no further findings.
2026-10-13 12:43:52 +08:00
Ysopwnableandfactory-droid[bot] a86deecac5 fix: align MCP archive contracts and documentation (#2478)
Reuse the domain ZIP format list for session schemas, verify full Harmony
CLI/MCP lifecycles, and correct native view guidance and audited docs drift.
Refresh locked dependency notices and gate inventory/provenance consistency,
including notice inputs in the cached documentation gate.

Fixes #2454

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-10-13 12:06:41 +08:00
Ysopwnable 172407787f fix(windows): preserve transient runtime admission failures (#2467)
Fixes #2257. Thanks to @chqcjq for the native self-test retry diagnosis in #2266.

Preserve retry disposition through analysis workflows. Native warm admission requires exact sharing/lock codes and affirmative pre-allocation evidence; cleanup ownership takes precedence. No automatic retry or new analysis cache.

Verified with real Windows 11 CLI, same-connection SDK MCP normal/conflict/recovery, the Windows native verifier, 99 focused tests and static/docs gates. Official npm 11.16.0 launcher sources were the application input. No IDA or Ghidra engine was used for this change. Win32 5 was not reproduced; no resolution claim for #1701/#2196. Performance measurements and limits are recorded in experiments/analysis-efficiency/windows-runtime-retry.md.
2026-10-13 11:42:54 +08:00
LuisandN0zoM1z0 bb154d1067 feat(browser): inspect retained aioquic qlog JSON captures
Inspect bounded offline aioquic1.5.0 JSON qlog0.3 and page retained event/transport facts with explicit trace and stream selectors. Preserve producer coordinates, exact numeric lexemes, global pre-selection fact scope and endpoint declaration uncertainty.

Verified four real HTTP/3 recordings with an independent interval oracle, public CLI/MCP/schema parity, auth exclusions, source-deletion views and actual decoder heap exhaustion. Unverified producer platforms and qlog-specific lifecycle induction remain documented.

Co-authored-by: LuisTaffelli <[email protected]>
Co-authored-by: N0zoM1z0 <[email protected]>
2026-10-13 03:24:05 +00:00
a2d8b94dd5 feat(fiddler): inspect native SAZ captures
Inspect bounded recorded raw HTTP/XML SAZ archives and page retained capture Evidence. Preserve exact stored bytes and provenance, validate ZIP/XML integrity, and require an enforceable decoder memory bound.

Verified 356 real recorded sessions against independent byte and metadata oracles, public CLI/MCP parity, retained pages, and related interface checks. Current Fiddler Everywhere GUI and non-Linux producer workflows remain unverified.

Co-authored-by: zahhak <[email protected]>
Co-authored-by: N0zoM1z0 <[email protected]>
2026-10-13 02:51:14 +00:00
N0zoM1z0 4773c152bc feat(website): add a persistent light and dark theme switch 2026-10-13 09:27:49 +08:00
Ysopwnable 37b7550ecc fix(ida): preserve native coverage and verify returned values (#2324)
Reject native callee successes without an explicit truncation marker while preserving provider failure reasons. Verify positive procedure inventory/search and function-result parity in the real-provider lane; support independent string/xref oracles and label their absence as unverified.

Verified with Windows IDA Pro 9.3: eight normal production CLI/MCP checks passed, and six real-provider response-fault cases reproduced old false positives and validated the correction. Windows IDA Free was not used. No personal paths or license registration information are included.

Repair inconsistent complete-file Ghidra test probe sizes after the shared ELF-header validation change, deriving sizes from the fixture buffers. Reproduced the three failures before the correction; 115 related installation/doctor and ELF tests pass afterward. Runtime parsing and installation behavior are unchanged; no real-Ghidra verification is claimed.

207 focused IDA tests and static/documentation checks passed. Automated review completed on d1e0b1095 without findings. CI run 38327862093 passed all 36 jobs, including Windows, all six test shards, coverage/timing, and real Apple CLI/MCP workflows.

Follow-up to #1544.
2026-10-13 08:44:18 +08:00