refactor: the kernel's packages live in the layer they belong to

internal/ was 141 packages side by side, so nothing but a reader's memory
said which were foundations and which assembled the rest. Each now sits in a
layer directory, and the directory is the declaration:

  base      L0  foundation with no domain in it
  contract  L1  types and interfaces the layers above agree on
  model, tools, safety, ext, state, platform
            L2  subsystems, peers of one another
  runtime   L3  the turn engine
  session   L4  the controller
  assembly  L5  the composition root
  frontend  L6  cli, serve, acp and the host adapters

Only paths change: package names, code and behaviour do not. Imports,
repolint and coverage baselines, sensitive paths, CI package lists and docs
follow the new paths; release notes keep the paths they were written with,
and sample paths inside tests and fixtures keep theirs.

repolint gains layer-order: a package may import its own layer and those
below it, read from where it lives. The 47 imports that point upward today
are recorded as that rule's opening debt (-allow-widen, a new rule's first
baseline) and can only go down. Most of it is config, which still reaches
into eight subsystems and is the next thing to take apart; the rest is
event, history and a few tools reaching into runtime for types that belong
in contract.
This commit is contained in:
yhh committed 2026-09-23 18:28:21 -07:00
1 parent 68bf9f7410
commit 394da0a313
2952 files changed
+6699 -6491

No files matched your search

+9 -9
View File
@@ -6,36 +6,36 @@
agent:
- changed-files:
- any-glob-to-any-file:
- 'internal/agent/**'
- 'internal/control/**'
- 'internal/runtime/agent/**'
- 'internal/session/control/**'
mcp:
- changed-files:
- any-glob-to-any-file:
- 'internal/plugin/**'
- 'internal/ext/plugin/**'
- 'internal/codegraph/**'
config:
- changed-files:
- any-glob-to-any-file:
- 'internal/config/**'
- 'internal/boot/**'
- 'internal/contract/config/**'
- 'internal/assembly/boot/**'
provider:
- changed-files:
- any-glob-to-any-file:
- 'internal/provider/**'
- 'internal/contract/provider/**'
skills:
- changed-files:
- any-glob-to-any-file:
- 'internal/skill/**'
- 'internal/tool/**'
- 'internal/ext/skill/**'
- 'internal/contract/tool/**'
tui:
- changed-files:
- any-glob-to-any-file:
- 'internal/cli/**'
- 'internal/frontend/cli/**'
desktop:
- changed-files:
+11 -11
View File
@@ -57,9 +57,9 @@ jobs:
# so only this clearly-unrelated set is safe to skip.
if echo "$files" | grep -qvE '^(docs/|release-notes/|workers/|benchmarks/|npm/|[^/]+\.md$)'; then desktop=true; fi
# sdk/go is a nested module invisible to root `go test ./...`;
# its DTOs are generated from internal/extension/protocol, so
# its DTOs are generated from internal/ext/extension/protocol, so
# both paths must trigger the sdk job.
if echo "$files" | grep -qE '^(sdk/|internal/extension/)'; then sdk=true; fi
if echo "$files" | grep -qE '^(sdk/|internal/ext/extension/)'; then sdk=true; fi
fi
fi
{ echo "code=$code"; echo "desktop=$desktop"; echo "sdk=$sdk"; } >> "$GITHUB_OUTPUT"
@@ -158,8 +158,8 @@ jobs:
# remains independently bounded by Go's per-package timeout below.
#
# That timeout is 8m, not 3m: across four consecutive runs of the same
# code, internal/boot measured 133s, 146s, 162s and then hit 180s, and
# internal/agent 82s, 92s, 144s and 180s — a 2.2x spread from runner
# code, internal/assembly/boot measured 133s, 146s, 162s and then hit 180s, and
# internal/runtime/agent 82s, 92s, 144s and 180s — a 2.2x spread from runner
# variance alone, with four heavy packages sharing four vCPUs. At 3m the
# step failed on slow runners without a code change; a hang still trips
# the 15 minute job budget above.
@@ -169,24 +169,24 @@ jobs:
env:
REASONIX_RELEASE_CACHE_GUARD: "1"
WINDOWS_SANDBOX_WAIT_MS: "20000"
run: go test -p 4 -timeout=8m ./internal/agent/... ./internal/appidentity/... ./internal/boot/... ./internal/checkpoint/... ./internal/cli/... ./internal/control/... ./internal/filelock/... ./internal/fileutil/... ./internal/hook/... ./internal/instruction/... ./internal/mcplaunch/... ./internal/notify/... ./internal/proc/... ./internal/remote/... ./internal/repair/... ./internal/sandbox/... ./internal/sysproxy/... ./internal/workspacelease/... ./cmd/...
run: go test -p 4 -timeout=8m ./internal/runtime/agent/... ./internal/platform/appidentity/... ./internal/assembly/boot/... ./internal/state/checkpoint/... ./internal/frontend/cli/... ./internal/session/control/... ./internal/base/filelock/... ./internal/base/fileutil/... ./internal/ext/hook/... ./internal/state/instruction/... ./internal/ext/mcplaunch/... ./internal/platform/notify/... ./internal/base/proc/... ./internal/platform/remote/... ./internal/platform/repair/... ./internal/safety/sandbox/... ./internal/base/sysproxy/... ./internal/state/workspacelease/... ./cmd/...
# The general Windows PR smoke list intentionally omits internal/tool.
# The general Windows PR smoke list intentionally omits internal/contract/tool.
# Keep the session-temp portability contract covered without widening the
# leg to every tool test: two real PowerShell launches must share the
# injected TMPDIR/TMP/TEMP directory.
- name: test (Windows session temp)
if: env.RUN_STEPS == 'true' && runner.os == 'Windows' && github.event_name == 'pull_request'
timeout-minutes: 3
run: go test -timeout=2m -run '^TestBashSharesSessionTempAcrossCalls$' ./internal/tool/builtin
run: go test -timeout=2m -run '^TestBashSharesSessionTempAcrossCalls$' ./internal/tools/builtin
# Shell execution contract: PowerShell identity, Chinese workspace paths,
# UTF-8 output, and ExitCode retention must gate PRs on native Windows.
# Keep this focused (not full ./internal/tool) so the smoke budget holds.
# Keep this focused (not full ./internal/contract/tool) so the smoke budget holds.
- name: test (Windows shell execution contract)
if: env.RUN_STEPS == 'true' && runner.os == 'Windows' && github.event_name == 'pull_request'
timeout-minutes: 5
run: go test -timeout=3m -run '^TestBashPowerShellExecuteDetailedContract$|^TestBashPowerShell51PreflightRejectsAndAndDetailed$|^TestBashPowerShellOutputIsUTF8$|^TestBashPowerShellSurfacesNonZeroExit$|^TestBashPowerShellRejectsChaining$' ./internal/tool/builtin
run: go test -timeout=3m -run '^TestBashPowerShellExecuteDetailedContract$|^TestBashPowerShell51PreflightRejectsAndAndDetailed$|^TestBashPowerShellOutputIsUTF8$|^TestBashPowerShellSurfacesNonZeroExit$|^TestBashPowerShellRejectsChaining$' ./internal/tools/builtin
# Full push suite still uses the same 8m package budget as Windows smoke:
# agent/boot/control already hit 180s package timeouts under runner load,
@@ -242,7 +242,7 @@ jobs:
if: github.event_name == 'pull_request'
env:
REASONIX_RELEASE_CACHE_GUARD: "1"
run: go test -race ./internal/agent/... ./internal/plugin/... ./internal/jobs/... ./internal/proc/... ./internal/sandbox/... ./internal/filelock/... ./internal/eventwire/... ./internal/remote/... ./internal/extension/... ./internal/boot/... ./internal/control/... ./internal/tool/...
run: go test -race ./internal/runtime/agent/... ./internal/ext/plugin/... ./internal/runtime/jobs/... ./internal/base/proc/... ./internal/safety/sandbox/... ./internal/base/filelock/... ./internal/contract/eventwire/... ./internal/platform/remote/... ./internal/ext/extension/... ./internal/assembly/boot/... ./internal/session/control/... ./internal/contract/tool/...
- name: test -race (full)
if: github.event_name != 'pull_request'
@@ -251,7 +251,7 @@ jobs:
run: go test -race ./...
# sdk/go is a nested stdlib-only module invisible to root `go test ./...`.
# Its DTOs are generated from internal/extension/protocol, and the
# Its DTOs are generated from internal/ext/extension/protocol, and the
# host-side conformance tests spawn the SDK example, so the job runs the
# same three-OS matrix as the root tests.
sdk:
+1 -1
View File
@@ -16,7 +16,7 @@ builds:
ldflags:
# Inject version identity for `reasonix version --verbose/--json` (Integration D/E).
# buildTimeUTC is the goreleaser run time (UTC), not vcs.time.
- -s -w -X main.version={{ .Tag }} -X main.gitCommit={{ .ShortCommit }} -X main.buildTimeUTC={{ .Date }} -X reasonix/internal/productdocs.linkedVersion={{ .Tag }} -X reasonix/internal/productdocs.linkedRevision={{ .Commit }}
- -s -w -X main.version={{ .Tag }} -X main.gitCommit={{ .ShortCommit }} -X main.buildTimeUTC={{ .Date }} -X reasonix/internal/tools/productdocs.linkedVersion={{ .Tag }} -X reasonix/internal/tools/productdocs.linkedRevision={{ .Commit }}
goos: [darwin, linux, windows]
goarch: [amd64, arm64]
+23 -23
View File
@@ -24,21 +24,21 @@ go test ./... # runs the full test suite
| Directory | Purpose |
|-----------|---------|
| `cmd/reasonix` | CLI entry point |
| `internal/agent` | Agent loop, session, coordinator |
| `internal/cli` | TUI, subcommands, setup wizard |
| `internal/control` | Transport-agnostic controller |
| `internal/config` | TOML configuration loading |
| `internal/tool/builtin` | Built-in tools (bash, read_file, …) |
| `internal/provider` | Model-backend abstraction |
| `internal/provider/openai` | OpenAI-compatible provider |
| `internal/plugin` | MCP client (stdio + HTTP) |
| `internal/event` | Typed event stream |
| `internal/hook` | Shell hooks (PreToolUse, …) |
| `internal/memory` | REASONIX.md hierarchy + auto-memory |
| `internal/skill` | Skill discovery from Markdown |
| `internal/sandbox` | OS-level sandboxing |
| `internal/serve` | HTTP/SSE server frontend |
| `internal/checkpoint` | Snapshot-based rewind |
| `internal/runtime/agent` | Agent loop, session, coordinator |
| `internal/frontend/cli` | TUI, subcommands, setup wizard |
| `internal/session/control` | Transport-agnostic controller |
| `internal/contract/config` | TOML configuration loading |
| `internal/tools/builtin` | Built-in tools (bash, read_file, …) |
| `internal/contract/provider` | Model-backend abstraction |
| `internal/model/openai` | OpenAI-compatible provider |
| `internal/ext/plugin` | MCP client (stdio + HTTP) |
| `internal/contract/event` | Typed event stream |
| `internal/ext/hook` | Shell hooks (PreToolUse, …) |
| `internal/state/memory` | REASONIX.md hierarchy + auto-memory |
| `internal/ext/skill` | Skill discovery from Markdown |
| `internal/safety/sandbox` | OS-level sandboxing |
| `internal/frontend/serve` | HTTP/SSE server frontend |
| `internal/state/checkpoint` | Snapshot-based rewind |
| `desktop/` | Studio: the Electron shell, the SPA it serves (separate Go module) |
| `docs/` | Engineering spec, migration guide |
@@ -113,8 +113,8 @@ For these changes:
```bash
go test ./... # all tests
go test ./internal/agent/ -v # verbose, one package
go test ./internal/tool/builtin/ -run TestGrep # one test
go test ./internal/runtime/agent/ -v # verbose, one package
go test ./internal/tools/builtin/ -run TestGrep # one test
```
### Code style
@@ -139,25 +139,25 @@ ci: add golangci-lint and govulncheck
## Adding a new built-in tool
1. Create `internal/tool/builtin/mytool.go`
1. Create `internal/tools/builtin/mytool.go`
2. Implement the `tool.Tool` interface: `Name()`, `Description()`, `Schema()`, `ReadOnly()`, `Execute()`
3. Register via `func init() { tool.RegisterBuiltin(myTool{}) }`
4. Add tests in `internal/tool/builtin/builtin_test.go` or a separate `mytool_test.go`
4. Add tests in `internal/tools/builtin/builtin_test.go` or a separate `mytool_test.go`
5. The tool is automatically available — `main` blank-imports `builtin`
## Adding a new model provider
(For MCP tool servers see `internal/plugin` instead — that's a different layer.)
(For MCP tool servers see `internal/ext/plugin` instead — that's a different layer.)
1. Create `internal/provider/myprovider/`
1. Create `internal/contract/provider/myprovider/`
2. Implement `provider.Provider`: `Name()`, `Stream()`
3. Register via `func init() { provider.Register("mykind", New) }`
4. The provider is available from config with `kind = "mykind"`
## Adding i18n strings
1. Add the field to `internal/i18n/i18n.go` (`Messages` struct)
2. Add the value in `internal/i18n/messages_en.go` and `messages_zh.go`
1. Add the field to `internal/base/i18n/i18n.go` (`Messages` struct)
2. Add the value in `internal/base/i18n/messages_en.go` and `messages_zh.go`
3. The `TestCatalogsComplete` test will fail if you miss a locale
## Submitting changes
+23 -23
View File
@@ -21,13 +21,13 @@ agent. It is the Reasonix analog of Claude Code's CLAUDE.md.
thinks, `TaskSpec` what this call wants, `CapabilityGrant` what it may touch,
`ContextRequest` what it starts from, `SchedulerPolicy` when it runs. Put a
field in whichever member decides its value — profiles carry ceilings, never
per-call values. `internal/agent/profile_boundary_test.go` enforces it.
per-call values. `internal/runtime/agent/profile_boundary_test.go` enforces it.
- Cache-first: the system-prompt prefix (base prompt, tools, declared prefix
configuration) must stay byte-stable across turns so DeepSeek's automatic
prefix cache stays warm. Never mutate it mid-session — ride the turn tail
instead (see `control.Compose`), under the rules in *Context projection*.
- Performance features land with an effect test at their final boundary
(`internal/boot/effect_test.go` pattern): assert what actually reaches the
(`internal/assembly/boot/effect_test.go` pattern): assert what actually reaches the
provider request, frontend sink, or trajectory through the real `boot.Build`
assembly. Component correctness is not system effectiveness.
- A mutex- or atomic-guarded struct is ratcheted on its **scalar** field count
@@ -48,7 +48,7 @@ agent. It is the Reasonix analog of Claude Code's CLAUDE.md.
knows a deadline expired rather than a socket closed, and a message is where
that knowledge goes to die: the reader is left matching words, or with
nothing. Across HTTP the identity is a dotted code through `refuse`;
`refusal-path` fails a new `http.Error` in `internal/serve`, and the parity
`refusal-path` fails a new `http.Error` in `internal/frontend/serve`, and the parity
test fails a code the frontend cannot say. Inside Go it is `errors.Is` on a
sentinel the wrapping preserves; `error-text` fails a new match against an
error message, following it one hop into a local because storing the text
@@ -196,7 +196,7 @@ prefix was never where these belonged wrongly; freshness ownership was missing.
canonical state, so a switch flipped and a file edited past every API are the
same question, and a change no projection renders is not a change.
`internal/boot/context_projection_test.go` holds all five at the provider
`internal/assembly/boot/context_projection_test.go` holds all five at the provider
boundary, with the skills listing and the standing instructions as the two
worked examples. A block is settled only once the turn carrying it reaches the
runner: a turn blocked by a hook or refused by an extension after composing put
@@ -231,7 +231,7 @@ file only if all of them land, so a failure midway leaves nothing half-edited.
## Vendor rates
Official list prices live in one place: `officialRates` in
`internal/billing/rates.go`, oldest generation first, the last being what a
`internal/model/billing/rates.go`, oldest generation first, the last being what a
model charges today. A price change is an **append, never an edit** — the
superseded rate is what lets an installed config be recognised as holding one
of ours and brought forward, instead of quoting a retired rate for the rest of
@@ -248,7 +248,7 @@ exits non-zero — unread is its own verdict and never counts as agreement.
## Curated presets
A preset changing shape reaches the installs that already have the old one
through `shippedPresets` in `internal/config/preset_upgrade.go`: one declared
through `shippedPresets` in `internal/contract/config/preset_upgrade.go`: one declared
shape per generation, and one upgrade that brings a matching entry forward. The
guard is the whole shape — catalog, window, default — because an entry holding
what we shipped is ours to move and anything else its user curated.
@@ -274,7 +274,7 @@ Run these **before every commit** to catch the fastest CI failures locally:
gofmt -w . # catches gofmt (saves ~13s CI)
go vet ./... # catches vet warnings (saves ~52s CI/lint)
make lint # golangci-lint at CI's pin + repolint
go test ./internal/tool/builtin/ ./internal/boot/ # catches tool/boot test breaks
go test ./internal/tools/builtin/ ./internal/assembly/boot/ # catches tool/boot test breaks
```
`make lint` runs both gates CI runs, at the version in `.golangci-version`;
@@ -326,21 +326,21 @@ can finish. Sensitivity is declared, never inferred: the host does not read it
out of how a path is spelled, which cannot tell `internal/auth` from
`session_write_authority.go`, or a trace file from a data race.
- sensitive: internal/permission/**
- sensitive: internal/sandbox/**
- sensitive: internal/shellsafe/**
- sensitive: internal/shellparse/**
- sensitive: internal/control/approval.go
- sensitive: internal/control/approval_bridge.go
- sensitive: internal/control/approval_orchestration.go
- sensitive: internal/providerbroker/**
- sensitive: internal/installsource/**
- sensitive: internal/plugin/**
- sensitive: internal/pluginpkg/**
- sensitive: internal/netclient/**
- sensitive: internal/redirectguard/**
- sensitive: internal/browser/**
- sensitive: internal/computer/**
- sensitive: internal/safety/permission/**
- sensitive: internal/safety/sandbox/**
- sensitive: internal/safety/shellsafe/**
- sensitive: internal/base/shellparse/**
- sensitive: internal/session/control/approval.go
- sensitive: internal/session/control/approval_bridge.go
- sensitive: internal/session/control/approval_orchestration.go
- sensitive: internal/model/providerbroker/**
- sensitive: internal/ext/installsource/**
- sensitive: internal/ext/plugin/**
- sensitive: internal/ext/pluginpkg/**
- sensitive: internal/base/netclient/**
- sensitive: internal/safety/redirectguard/**
- sensitive: internal/platform/browser/**
- sensitive: internal/platform/computer/**
One declaration, two effects: the same list is also the coverage gate's subject.
`make coverage-gate` holds each path to the coverage it already has, because
@@ -376,7 +376,7 @@ moving a number here must not move the promise.
establishes nothing and the mutation stays unproven.
- Symlinks are recorded by `Lstat`, so a write through one lands outside what
the walk compares. Confining the resolved target is the sandbox's job.
- `internal/sandbox` confines writes to the workspace, configured extras, temp
- `internal/safety/sandbox` confines writes to the workspace, configured extras, temp
and toolchain caches — on macOS and Linux. Windows has no OS-level bash
sandbox, so there nothing the host enforces bounds `Writable`.
- The governed host authorities are a *named* set — ssh-agent, docker, podman.
+1 -1
View File
@@ -11,7 +11,7 @@ import (
"sort"
"strings"
"reasonix/internal/skill"
"reasonix/internal/ext/skill"
)
// detector answers one question: has the thing the model would be sent changed?
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"path/filepath"
"strings"
"reasonix/internal/skill"
"reasonix/internal/ext/skill"
)
type verdict struct {
+7 -7
View File
@@ -18,13 +18,13 @@ import (
"strings"
"time"
"reasonix/internal/ablation"
"reasonix/internal/agent"
"reasonix/internal/event"
"reasonix/internal/provider"
_ "reasonix/internal/provider/openai"
"reasonix/internal/tokencount"
"reasonix/internal/tool"
"reasonix/internal/base/tokencount"
"reasonix/internal/contract/ablation"
"reasonix/internal/contract/event"
"reasonix/internal/contract/provider"
"reasonix/internal/contract/tool"
_ "reasonix/internal/model/openai"
"reasonix/internal/runtime/agent"
)
const (
+5 -5
View File
@@ -6,9 +6,9 @@ import (
"strings"
"unicode"
"reasonix/internal/agent"
"reasonix/internal/provider"
"reasonix/internal/tool"
"reasonix/internal/contract/provider"
"reasonix/internal/contract/tool"
"reasonix/internal/runtime/agent"
)
// probeAnswerContract rides with every probe question. A context full of tool
@@ -240,8 +240,8 @@ func revisionProbes() []probe {
{
class: "late-constraint",
plantAt: 3,
plant: userTurn("New hard rule from here on: never edit anything under internal/store/."),
question: "Are you allowed to edit files under internal/store/? Answer yes or no.",
plant: userTurn("New hard rule from here on: never edit anything under internal/state/store/."),
question: "Are you allowed to edit files under internal/state/store/? Answer yes or no.",
want: []string{"no"},
reject: []string{"yes"},
},
+2 -2
View File
@@ -4,8 +4,8 @@ import (
"fmt"
"strings"
"reasonix/internal/agent"
"reasonix/internal/provider"
"reasonix/internal/contract/provider"
"reasonix/internal/runtime/agent"
)
// A generation is one round of work followed by one compaction. Compaction
+5 -5
View File
@@ -13,11 +13,11 @@ import (
"strings"
"time"
"reasonix/internal/agent"
"reasonix/internal/event"
"reasonix/internal/provider"
_ "reasonix/internal/provider/openai"
"reasonix/internal/tool"
"reasonix/internal/contract/event"
"reasonix/internal/contract/provider"
"reasonix/internal/contract/tool"
_ "reasonix/internal/model/openai"
"reasonix/internal/runtime/agent"
)
const (
+7 -7
View File
@@ -7,13 +7,13 @@ import (
"fmt"
"strings"
"reasonix/internal/ablation"
"reasonix/internal/agent"
"reasonix/internal/boot"
"reasonix/internal/event"
"reasonix/internal/provider"
"reasonix/internal/tool"
_ "reasonix/internal/tool/builtin"
"reasonix/internal/assembly/boot"
"reasonix/internal/contract/ablation"
"reasonix/internal/contract/event"
"reasonix/internal/contract/provider"
"reasonix/internal/contract/tool"
"reasonix/internal/runtime/agent"
_ "reasonix/internal/tools/builtin"
)
// A projection is what the agent believes; a provider.Request is what the model
+2 -2
View File
@@ -10,8 +10,8 @@ import (
"strconv"
"strings"
"reasonix/internal/provider"
"reasonix/internal/tokencount"
"reasonix/internal/base/tokencount"
"reasonix/internal/contract/provider"
)
// Every judgement here reads a tool call's name and its JSON arguments, or a
@@ -5,7 +5,7 @@ import (
"strings"
"testing"
"reasonix/internal/provider"
"reasonix/internal/contract/provider"
)
// The scorer decides what the pilot concludes, so it is held to the same rule
+2 -2
View File
@@ -4,8 +4,8 @@ import (
"fmt"
"math/rand"
"reasonix/internal/agent"
"reasonix/internal/provider"
"reasonix/internal/contract/provider"
"reasonix/internal/runtime/agent"
)
// Synthetic history on purpose: an answer that exists in the workspace is
+5 -5
View File
@@ -8,11 +8,11 @@ import (
"path/filepath"
"strings"
"reasonix/internal/ablation"
"reasonix/internal/agent"
"reasonix/internal/event"
"reasonix/internal/provider"
"reasonix/internal/tool"
"reasonix/internal/contract/ablation"
"reasonix/internal/contract/event"
"reasonix/internal/contract/provider"
"reasonix/internal/contract/tool"
"reasonix/internal/runtime/agent"
)
// A fixture is a real session that has really been compacted: no bench-only
+3 -3
View File
@@ -7,9 +7,9 @@ import (
"slices"
"strings"
"reasonix/internal/ablation"
"reasonix/internal/provider"
"reasonix/internal/retrieval"
"reasonix/internal/base/retrieval"
"reasonix/internal/contract/ablation"
"reasonix/internal/contract/provider"
)
// Preflight is what makes a real run worth paying for. An answer the model can
@@ -7,7 +7,7 @@ import (
"sort"
"strings"
"reasonix/internal/retrieval"
"reasonix/internal/base/retrieval"
)
// The host probe ranks every target first, so the engine is not what makes a
+8 -8
View File
@@ -11,14 +11,14 @@ import (
"strings"
"time"
"reasonix/internal/ablation"
"reasonix/internal/agent"
"reasonix/internal/boot"
"reasonix/internal/event"
"reasonix/internal/provider"
_ "reasonix/internal/provider/openai"
"reasonix/internal/tool"
_ "reasonix/internal/tool/builtin"
"reasonix/internal/assembly/boot"
"reasonix/internal/contract/ablation"
"reasonix/internal/contract/event"
"reasonix/internal/contract/provider"
"reasonix/internal/contract/tool"
_ "reasonix/internal/model/openai"
"reasonix/internal/runtime/agent"
_ "reasonix/internal/tools/builtin"
)
// A run is one recall question against a fixture the preflight has already
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"strconv"
"strings"
"reasonix/internal/provider"
"reasonix/internal/contract/provider"
)
// scriptedProvider walks the chain a competent model would: search, read the
+5 -5
View File
@@ -8,11 +8,11 @@ import (
"path/filepath"
"strings"
"reasonix/internal/ablation"
"reasonix/internal/agent"
"reasonix/internal/event"
"reasonix/internal/retrieval"
"reasonix/internal/tool"
"reasonix/internal/base/retrieval"
"reasonix/internal/contract/ablation"
"reasonix/internal/contract/event"
"reasonix/internal/contract/tool"
"reasonix/internal/runtime/agent"
)
// TargetHit is not EvidenceSufficient: a rank-1 hit can still hand over a
+2 -2
View File
@@ -11,7 +11,7 @@ to this gate and no amount of running it accumulates evidence about it.
Two different claims need two different kinds of evidence.
That the legacy derivation can be bypassed is already proven deterministically
by `internal/agent/project_check_probe_test.go`: a delivery turn that rewrites
by `internal/runtime/agent/project_check_probe_test.go`: a delivery turn that rewrites
its own `- verify:` line and runs only the replacement finalizes, never having
run the criterion the task began under. That test needs no corpus.
@@ -76,7 +76,7 @@ So the chain this corpus set out to pin breaks at its first link. The restored
baseline was not A, and every claim after that fails with it.
One path is left and is not tested here. `DeliveryCheckpoint` carries
`BaselineChecks` and is persisted with goal state (`internal/control/goal.go`,
`BaselineChecks` and is persisted with goal state (`internal/session/control/goal.go`,
json-tagged); `RestoreDeliveryCheckpoint` seeds a rebuilt executor, and the turn
loop only clears the checkpoint when the scope id changes. A Goal that survives
a restart across a changed declaration would therefore keep the old baseline
+2 -2
View File
@@ -137,7 +137,7 @@ it, and its parent call stays empty. `SubagentMeta` carries both answers, and
this is the first place they differ — until a host-started run existed, every
durable execution came from a tool call and one field could hold both.
`TestDelegationClassesStayApart` in `internal/boot` holds the classification, and
`TestDelegationClassesStayApart` in `internal/assembly/boot` holds the classification, and
holds it where a completed run cannot: what the store answers at the one instant
a child is inside the provider. A check made afterwards cannot tell a recorded
execution from an unrecorded one that happened to finish, because completion
@@ -1105,7 +1105,7 @@ released.
## Rebuilding the graph
`internal/execgraph` folds the journal, the store's child terminals, and this
`internal/state/execgraph` folds the journal, the store's child terminals, and this
process's live executions into a graph. It recomputes rather than restores:
nothing reads a file or emits an event, and the same inputs always give the
same picture.
+3 -3
View File
@@ -8,9 +8,9 @@ import (
"strings"
"time"
"reasonix/internal/agentgraph"
"reasonix/internal/control"
"reasonix/internal/execjournal"
"reasonix/internal/contract/agentgraph"
"reasonix/internal/session/control"
"reasonix/internal/state/execjournal"
)
// armFleetActiveStore asks whether the sub-agent store can be asked about a
+4 -4
View File
@@ -7,10 +7,10 @@ import (
"path/filepath"
"strings"
"reasonix/internal/agent"
"reasonix/internal/config"
"reasonix/internal/memory"
"reasonix/internal/provider"
"reasonix/internal/contract/config"
"reasonix/internal/contract/provider"
"reasonix/internal/runtime/agent"
"reasonix/internal/state/memory"
)
// arm is one death-and-resume run. Lever runs between the two processes and is
+2 -2
View File
@@ -8,8 +8,8 @@ import (
"strings"
"time"
"reasonix/internal/control"
"reasonix/internal/provider"
"reasonix/internal/contract/provider"
"reasonix/internal/session/control"
)
// Where a stop goes — and, first, whose stop it is. A controller owns the turns
+4 -4
View File
@@ -7,10 +7,10 @@ import (
"strings"
"time"
"reasonix/internal/agent"
"reasonix/internal/agentgraph"
"reasonix/internal/control"
"reasonix/internal/execgraph"
"reasonix/internal/contract/agentgraph"
"reasonix/internal/runtime/agent"
"reasonix/internal/session/control"
"reasonix/internal/state/execgraph"
)
// The derivability arms. Everything before them asked what survives; these ask
+3 -3
View File
@@ -9,9 +9,9 @@ import (
"strings"
"time"
"reasonix/internal/agentgraph"
"reasonix/internal/control"
"reasonix/internal/provider"
"reasonix/internal/contract/agentgraph"
"reasonix/internal/contract/provider"
"reasonix/internal/session/control"
)
// The two ephemeral entry points, read against the execution read model's own
+3 -3
View File
@@ -10,9 +10,9 @@ import (
"strings"
"time"
"reasonix/internal/agentgraph"
"reasonix/internal/control"
"reasonix/internal/provider"
"reasonix/internal/contract/agentgraph"
"reasonix/internal/contract/provider"
"reasonix/internal/session/control"
)
// The three fan-out arms. Each dies at a different point in one fleet's life,
+4 -4
View File
@@ -6,10 +6,10 @@ import (
"sort"
"strings"
"reasonix/internal/agent"
"reasonix/internal/agentgraph"
"reasonix/internal/execgraph"
"reasonix/internal/execjournal"
"reasonix/internal/contract/agentgraph"
"reasonix/internal/runtime/agent"
"reasonix/internal/state/execgraph"
"reasonix/internal/state/execjournal"
)
// How a run graph can stand after the process that built it exits. Three are
+2 -2
View File
@@ -9,8 +9,8 @@ import (
"sync/atomic"
"time"
"reasonix/internal/agentgraph"
"reasonix/internal/control"
"reasonix/internal/contract/agentgraph"
"reasonix/internal/session/control"
)
// The interactive host-initiated arms, named for the one surface they measure: a
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"strings"
"time"
"reasonix/internal/control"
"reasonix/internal/session/control"
)
// Two trees, read at once. A stop aimed at a turn must close the turn's own
+4 -4
View File
@@ -8,10 +8,10 @@ import (
"slices"
"time"
"reasonix/internal/agentgraph"
"reasonix/internal/control"
"reasonix/internal/event"
"reasonix/internal/provider"
"reasonix/internal/contract/agentgraph"
"reasonix/internal/contract/event"
"reasonix/internal/contract/provider"
"reasonix/internal/session/control"
)
// The four single-delegation arms. A lone task is not another executor: it
+3 -3
View File
@@ -5,9 +5,9 @@ import (
"sort"
"strings"
"reasonix/internal/agentgraph"
"reasonix/internal/execgraph"
"reasonix/internal/execjournal"
"reasonix/internal/contract/agentgraph"
"reasonix/internal/state/execgraph"
"reasonix/internal/state/execjournal"
)
// What a lone delegation leaves behind, layer by layer. The columns are the
+7 -7
View File
@@ -10,13 +10,13 @@ import (
"sort"
"strings"
"reasonix/internal/agent"
"reasonix/internal/agentgraph"
"reasonix/internal/control"
"reasonix/internal/evidence"
"reasonix/internal/execjournal"
"reasonix/internal/provider"
"reasonix/internal/store"
"reasonix/internal/contract/agentgraph"
"reasonix/internal/contract/provider"
"reasonix/internal/runtime/agent"
"reasonix/internal/runtime/evidence"
"reasonix/internal/session/control"
"reasonix/internal/state/execjournal"
"reasonix/internal/state/store"
)
// Observation is everything one phase can read about a session without asking a
+3 -3
View File
@@ -6,9 +6,9 @@ import (
"os"
"time"
"reasonix/internal/agent"
"reasonix/internal/checkpoint"
"reasonix/internal/control"
"reasonix/internal/runtime/agent"
"reasonix/internal/session/control"
"reasonix/internal/state/checkpoint"
)
// probeTurns is enough conversation for a fold to have a region to work on:
+4 -4
View File
@@ -10,10 +10,10 @@ import (
"sync"
"time"
"reasonix/internal/agentgraph"
"reasonix/internal/boot"
"reasonix/internal/control"
"reasonix/internal/event"
"reasonix/internal/assembly/boot"
"reasonix/internal/contract/agentgraph"
"reasonix/internal/contract/event"
"reasonix/internal/session/control"
)
// armRoot names the four directories one arm owns. Home and Workspace are
+2 -2
View File
@@ -8,8 +8,8 @@ import (
"strings"
"time"
"reasonix/internal/agentgraph"
"reasonix/internal/control"
"reasonix/internal/contract/agentgraph"
"reasonix/internal/session/control"
)
// The scheduler-wait arms. Each dies with one item ready and refused admission,
+1 -1
View File
@@ -11,7 +11,7 @@ import (
"sync"
"sync/atomic"
"reasonix/internal/provider"
"reasonix/internal/contract/provider"
)
// newScripted builds the provider with its synchronisation channels open. The
+4 -4
View File
@@ -10,10 +10,10 @@ import (
"strings"
"time"
"reasonix/internal/agent"
"reasonix/internal/control"
"reasonix/internal/provider"
"reasonix/internal/skill"
"reasonix/internal/contract/provider"
"reasonix/internal/ext/skill"
"reasonix/internal/runtime/agent"
"reasonix/internal/session/control"
)
// The skill-runner classification arms. They ask what kind of execution a
+2 -2
View File
@@ -8,8 +8,8 @@ import (
"strings"
"time"
"reasonix/internal/agentgraph"
"reasonix/internal/control"
"reasonix/internal/contract/agentgraph"
"reasonix/internal/session/control"
)
// The terminal-disposition arms. SETTLED says an opening is no longer active
+7 -7
View File
@@ -12,13 +12,13 @@ import (
"sync"
"time"
"reasonix/internal/agentgraph"
"reasonix/internal/config"
"reasonix/internal/control"
"reasonix/internal/event"
"reasonix/internal/execjournal"
"reasonix/internal/provider"
"reasonix/internal/serve"
"reasonix/internal/contract/agentgraph"
"reasonix/internal/contract/config"
"reasonix/internal/contract/event"
"reasonix/internal/contract/provider"
"reasonix/internal/frontend/serve"
"reasonix/internal/session/control"
"reasonix/internal/state/execjournal"
)
// armUIGraphMixed is the only arm that reads the frontend rather than the host.
+1 -1
View File
@@ -35,5 +35,5 @@ across three switches, with no miss spike at either. The absent surface is a byt
cache entry serves both.
This is what `Registry.ProviderSchemas` is built on: stable tools first,
contextual ones after, each sorted. `internal/tool/provider_surface_test.go`
contextual ones after, each sorted. `internal/contract/tool/provider_surface_test.go`
holds the shape — the segment boundary is the property this benchmark priced.
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"slices"
"strings"
"reasonix/internal/evidence"
"reasonix/internal/runtime/evidence"
)
// The terminal-barrier counterfactual: what a barrier at a child's first
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"testing"
"time"
"reasonix/internal/testenv"
"reasonix/internal/base/testenv"
)
func writeTaskVerify(t *testing.T, taskDir, script string) {
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
"reasonix/internal/testenv"
"reasonix/internal/base/testenv"
)
func writeArm(t *testing.T, dir, name string, results []result) string {
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
"reasonix/internal/testenv"
"reasonix/internal/base/testenv"
)
const corpusDir = "../../benchmarks/e2e"
+4 -4
View File
@@ -11,8 +11,8 @@ import (
"time"
"unicode/utf8"
"reasonix/internal/ablation"
"reasonix/internal/shellparse"
"reasonix/internal/base/shellparse"
"reasonix/internal/contract/ablation"
)
type diffOpts struct {
@@ -423,8 +423,8 @@ func parseCoverProfile(repo, path string) map[string][]coverBlock {
return out
}
// repoRelFromModulePath turns "reasonix/internal/agent/foo.go" into
// "internal/agent/foo.go" by dropping the first path element (the module root).
// repoRelFromModulePath turns "reasonix/internal/runtime/agent/foo.go" into
// "internal/runtime/agent/foo.go" by dropping the first path element (the module root).
func repoRelFromModulePath(p string) string {
// Strip the full module prefix; a generic first-segment cut mis-strips a multi-segment module path.
prefix := "reasonix/"
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"strings"
"testing"
"reasonix/internal/testenv"
"reasonix/internal/base/testenv"
)
func TestRunTestsAllowsStaticEnvAssignment(t *testing.T) {
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"strings"
)
// fanoutMetrics mirrors internal/cli.RunMetrics's field of the same name: what
// fanoutMetrics mirrors internal/frontend/cli.RunMetrics's field of the same name: what
// a run's fan-outs cost in wall clock against what the same work costs one at a
// time. The agent folds it from the run graph, which is the only record of it.
type fanoutMetrics struct {
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"strings"
"testing"
"reasonix/internal/testenv"
"reasonix/internal/base/testenv"
)
// A failed task is only actionable if the record says what the agent actually
+7 -7
View File
@@ -17,10 +17,10 @@ import (
"github.com/BurntSushi/toml"
"reasonix/internal/ablation"
"reasonix/internal/config"
"reasonix/internal/control"
fileencoding "reasonix/internal/fileutil/encoding"
fileencoding "reasonix/internal/base/fileutil/encoding"
"reasonix/internal/contract/ablation"
"reasonix/internal/contract/config"
"reasonix/internal/session/control"
)
type task struct {
@@ -55,7 +55,7 @@ type runMetrics struct {
CompletionTokens int `json:"completion_tokens"`
CacheHitTokens int `json:"cache_hit_tokens"`
CacheMissTokens int `json:"cache_miss_tokens"`
// PrefixChangeReasonCounts mirrors internal/cli.RunMetrics's field of the
// PrefixChangeReasonCounts mirrors internal/frontend/cli.RunMetrics's field of the
// same name: per-run tallies of why the cache prefix changed (e.g.
// "compact_auto", "snip", "tools"), omitempty for older metrics files.
PrefixChangeReasonCounts map[string]int `json:"prefix_change_reason_counts,omitempty"`
@@ -67,7 +67,7 @@ type runMetrics struct {
Currency string `json:"currency"`
Compactions int `json:"compactions"`
// Delegation counters mirror internal/cli.RunMetrics. They are what makes a
// Delegation counters mirror internal/frontend/cli.RunMetrics. They are what makes a
// single-agent arm comparable against a delegated one for the same model.
SubagentRuns int `json:"subagent_runs,omitempty"`
SubagentNestedRuns int `json:"subagent_nested_runs,omitempty"`
@@ -84,7 +84,7 @@ type runMetrics struct {
ParentNamedFiles int `json:"parent_named_files,omitempty"`
ChildEvidencePaths int `json:"child_evidence_paths,omitempty"`
ChildDiscoveredPaths int `json:"child_discovered_paths,omitempty"`
// Fanout mirrors internal/cli.RunMetrics: fan-out timing folded from the run
// Fanout mirrors internal/frontend/cli.RunMetrics: fan-out timing folded from the run
// graph, which is where a scheduling wait is recorded and nowhere else.
Fanout *fanoutMetrics `json:"fanout,omitempty"`
// Optional Delivery capability counters (omitempty for baseline/old metrics).
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"strings"
"testing"
"reasonix/internal/testenv"
"reasonix/internal/base/testenv"
)
func TestRenderMechanismLedgerSplitsFiredVsQuiet(t *testing.T) {
+1 -1
View File
@@ -13,7 +13,7 @@ import (
"path/filepath"
"strings"
"reasonix/internal/config"
"reasonix/internal/contract/config"
)
// seedTaskMemory populates stateHome's memory store from the task's memory/
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
"reasonix/internal/testenv"
"reasonix/internal/base/testenv"
)
func TestScanMemoryRecallCountsAndPointOfUse(t *testing.T) {
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"testing"
"github.com/BurntSushi/toml"
"reasonix/internal/testenv"
"reasonix/internal/base/testenv"
)
const twoProviderConfig = `
+2 -2
View File
@@ -5,7 +5,7 @@ import (
"strings"
"testing"
"reasonix/internal/cli"
"reasonix/internal/frontend/cli"
)
// jsonTags collects a struct's JSON field names, descending into embedded and
@@ -48,7 +48,7 @@ func TestBenchMetricsOnlyReadTagsTheAgentEmits(t *testing.T) {
}
if len(orphaned) > 0 {
t.Fatalf("e2ebench reads metrics tags no agent writes: %v\n"+
"either internal/cli.RunMetrics lost them in a rename, or the bench "+
"either internal/frontend/cli.RunMetrics lost them in a rename, or the bench "+
"invented them; both leave the field zero in every report", orphaned)
}
}
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"strings"
"testing"
"reasonix/internal/testenv"
"reasonix/internal/base/testenv"
)
func writeTrajectory(t *testing.T, name string, lines []string) string {
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"fmt"
"strings"
"reasonix/internal/ablation"
"reasonix/internal/contract/ablation"
)
// experimentAxes is the validated set of fixed axes one suite invocation runs
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"reflect"
"testing"
"reasonix/internal/ablation"
"reasonix/internal/contract/ablation"
)
func TestAppendBenchmarkProfileArgsBaselineIsByteIdentical(t *testing.T) {
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"strings"
"testing"
"reasonix/internal/testenv"
"reasonix/internal/base/testenv"
)
// requireShellStub skips where a #!/usr/bin/env bash stub cannot be executed.
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
"reasonix/internal/testenv"
"reasonix/internal/base/testenv"
)
// writeTraj lays down a trajectory whose rounds all report prefix hash "p1".
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"sort"
"strings"
"reasonix/internal/event"
"reasonix/internal/contract/event"
)
// conversationSources carry the session's tools and history. Every other
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"slices"
"strings"
"reasonix/internal/ablation"
"reasonix/internal/contract/ablation"
)
// SWE-bench mode runs the agent inside the official per-instance evaluation
+2 -2
View File
@@ -10,8 +10,8 @@ import (
"strings"
"time"
"reasonix/internal/ablation"
fileencoding "reasonix/internal/fileutil/encoding"
fileencoding "reasonix/internal/base/fileutil/encoding"
"reasonix/internal/contract/ablation"
)
type swebenchOpts struct {
+2 -2
View File
@@ -8,8 +8,8 @@ import (
"github.com/BurntSushi/toml"
"reasonix/internal/ablation"
"reasonix/internal/config"
"reasonix/internal/contract/ablation"
"reasonix/internal/contract/config"
)
// The harness prints an unmangled local image key but pulls a mangled one; the
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"slices"
"strings"
"reasonix/internal/evidence"
"reasonix/internal/runtime/evidence"
)
// trajectorySummary is the harness-side digest of one run's trajectory file:
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"strings"
"testing"
"reasonix/internal/testenv"
"reasonix/internal/base/testenv"
)
func TestSummarizeTrajectoryAttributesTimeAndSkipsTruncatedTail(t *testing.T) {
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"fmt"
"log"
"reasonix/internal/extension/protocolgen"
"reasonix/internal/ext/extension/protocolgen"
)
func main() {
+1 -1
View File
@@ -1,6 +1,6 @@
// Command reasonix-plugin-example is a reference Reasonix plugin: a minimal MCP stdio
// server speaking newline-delimited JSON-RPC 2.0 on stdin/stdout. It exists to
// document the contract end-to-end (the protocol the internal/plugin client
// document the contract end-to-end (the protocol the internal/ext/plugin client
// drives) and to give users a working example to copy.
//
// Wire it up in reasonix.toml:
+15 -15
View File
@@ -20,23 +20,23 @@ import (
"strings"
"syscall"
"reasonix/internal/appupdate"
"reasonix/internal/boot"
"reasonix/internal/config"
"reasonix/internal/event"
"reasonix/internal/i18n"
"reasonix/internal/instanceid"
"reasonix/internal/notify"
"reasonix/internal/remotehost"
"reasonix/internal/serve"
"reasonix/internal/surface"
"reasonix/internal/traystate"
"reasonix/internal/update"
"reasonix/internal/assembly/boot"
"reasonix/internal/base/i18n"
"reasonix/internal/contract/config"
"reasonix/internal/contract/event"
"reasonix/internal/contract/surface"
"reasonix/internal/frontend/remotehost"
"reasonix/internal/frontend/serve"
"reasonix/internal/frontend/traystate"
"reasonix/internal/platform/appupdate"
"reasonix/internal/platform/instanceid"
"reasonix/internal/platform/notify"
"reasonix/internal/platform/update"
// Kinds register from init, so a binary builds only what it links. Without
// these every Anthropic model answers "unknown kind" at switch time.
_ "reasonix/internal/provider/anthropic"
_ "reasonix/internal/provider/openai"
_ "reasonix/internal/provider/responses"
_ "reasonix/internal/model/anthropic"
_ "reasonix/internal/model/openai"
_ "reasonix/internal/model/responses"
)
var version = "dev"
+7 -7
View File
@@ -13,13 +13,13 @@ import (
"testing"
"time"
"reasonix/internal/config"
"reasonix/internal/control"
"reasonix/internal/event"
"reasonix/internal/serve"
"reasonix/internal/surface"
"reasonix/internal/testenv"
"reasonix/internal/traystate"
"reasonix/internal/base/testenv"
"reasonix/internal/contract/config"
"reasonix/internal/contract/event"
"reasonix/internal/contract/surface"
"reasonix/internal/frontend/serve"
"reasonix/internal/frontend/traystate"
"reasonix/internal/session/control"
)
func TestMain(m *testing.M) {
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"path/filepath"
"strings"
"reasonix/internal/packagegrant"
"reasonix/internal/platform/packagegrant"
)
// stripPackageGrants works on the directory the application runs from and is
@@ -7,7 +7,7 @@ import (
"path/filepath"
"testing"
"reasonix/internal/packagegrant"
"reasonix/internal/platform/packagegrant"
)
func TestStripPackageGrantsOnlyAnswersForAnApplication(t *testing.T) {
+2 -2
View File
@@ -6,8 +6,8 @@ import (
"go/token"
"testing"
"reasonix/internal/config"
"reasonix/internal/i18n"
"reasonix/internal/base/i18n"
"reasonix/internal/contract/config"
)
// A capability this host implements and does not hand to its hub is one the
+7 -7
View File
@@ -5,15 +5,15 @@ import (
"os"
"runtime/debug"
"reasonix/internal/cli"
"reasonix/internal/config"
"reasonix/internal/crashreport"
"reasonix/internal/contract/config"
"reasonix/internal/frontend/cli"
"reasonix/internal/platform/crashreport"
// Blank imports wire compile-time built-ins into their registries.
_ "reasonix/internal/provider/anthropic"
_ "reasonix/internal/provider/openai"
_ "reasonix/internal/provider/responses"
_ "reasonix/internal/tool/builtin"
_ "reasonix/internal/model/anthropic"
_ "reasonix/internal/model/openai"
_ "reasonix/internal/model/responses"
_ "reasonix/internal/tools/builtin"
)
// Build identity injected via -ldflags (see Makefile). version remains the
+3 -3
View File
@@ -4,9 +4,9 @@ import (
"strings"
"testing"
"reasonix/internal/config"
"reasonix/internal/crashreport"
"reasonix/internal/testenv"
"reasonix/internal/base/testenv"
"reasonix/internal/contract/config"
"reasonix/internal/platform/crashreport"
)
func TestRunWithCrashCaptureRecordsAndReraises(t *testing.T) {
+3 -3
View File
@@ -2,7 +2,7 @@
A desktop window around the Reasonix Go kernel. The window hosts a React SPA,
and every request the SPA makes reaches the kernel's own HTTP server
(`internal/serve`) over loopback, so Studio, `reasonix serve` and the remote UI
(`internal/frontend/serve`) over loopback, so Studio, `reasonix serve` and the remote UI
all answer the same routes.
```
@@ -19,7 +19,7 @@ all answer the same routes.
│ spawns, holds the lease │
┌───────────────┴────────────────────────────▼─────────────────┐
│ cmd/reasonix-studio-host (main module, CGO-free) │
│ internal/boot.Build → internal/control.Controller │
│ internal/assembly/boot.Build → internal/session/control.Controller │
│ (same assembly the CLI uses: providers, tools, gate, …) │
└───────────────────────────────────────────────────────────────┘
```
@@ -35,7 +35,7 @@ are written down in [`docs/STUDIO_SHELL_BOUNDARIES.md`](../docs/STUDIO_SHELL_BOU
| --- | --- |
| `electron/` | the shell: main process, preload bridge, packaging |
| `frontend-next/` | the SPA it serves |
| `internal/update/` | manifest, download, verify, apply — shared by the shell and the helper |
| `internal/platform/update/` | manifest, download, verify, apply — shared by the shell and the helper |
| `cmd/update-helper/` | the elevated half of an update (dpkg on Linux, versioned install on Windows) |
| `cmd/studio-manifest/`, `cmd/sign/` | release-side tools |
| `internal/winuninstall/` | taking a previous Windows install over |
+3 -3
View File
@@ -33,7 +33,7 @@ import (
"aead.dev/minisign"
"reasonix/internal/update"
"reasonix/internal/platform/update"
)
// platforms are the manifest keys we publish. A built artifact is matched to a key
@@ -138,7 +138,7 @@ func verifyFile(path string) error {
// genKey generates a fresh minisign key pair, writing the encrypted private key
// (reasonix.key) and the public key (reasonix.pub) into dir. The password comes
// from $MINISIGN_PASSWORD. The public key is printed — it's safe to publish; embed
// it in internal/update/verify.go. The private key never leaves dir.
// it in internal/platform/update/verify.go. The private key never leaves dir.
func genKey(dir string) error {
pw := os.Getenv("MINISIGN_PASSWORD")
if strings.TrimSpace(pw) == "" {
@@ -169,7 +169,7 @@ func genKey(dir string) error {
}
fmt.Printf("private key -> %s (keep secret; this is the MINISIGN_PRIVATE_KEY value)\n", keyPath)
fmt.Printf("public key -> %s\n\n", pubPath)
fmt.Printf("public key (embed in internal/update/verify.go, key ID %016X):\n%s\n", pub.ID(), pubText)
fmt.Printf("public key (embed in internal/platform/update/verify.go, key ID %016X):\n%s\n", pub.ID(), pubText)
return nil
}
+1 -1
View File
@@ -10,7 +10,7 @@ import (
"aead.dev/minisign"
"reasonix/internal/update"
"reasonix/internal/platform/update"
)
// TestSignFiles signs a file with a throwaway key pair (injected via env, exactly
@@ -7,7 +7,7 @@ import (
"slices"
"testing"
"reasonix/internal/update"
"reasonix/internal/platform/update"
)
// archMap is desktop/electron/arch.json: what the packager builds for, and what
+1 -1
View File
@@ -17,7 +17,7 @@ import (
"path/filepath"
"strings"
"reasonix/internal/update"
"reasonix/internal/platform/update"
)
const artifactPrefix = "ReasonixStudio-"
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"strings"
"testing"
"reasonix/internal/update"
"reasonix/internal/platform/update"
)
func TestManifestRecordsEveryArtifactWithItsSignature(t *testing.T) {
+1 -1
View File
@@ -21,7 +21,7 @@ import (
"strings"
"syscall"
"reasonix/internal/update"
"reasonix/internal/platform/update"
)
// Stable exit codes observed by the desktop installer.
+1 -1
View File
@@ -13,7 +13,7 @@ import (
"aead.dev/minisign"
"reasonix/internal/tempdir"
"reasonix/internal/base/tempdir"
)
func TestSanitizeHelperErrorStripsPaths(t *testing.T) {
+2 -2
View File
@@ -21,8 +21,8 @@ import (
"golang.org/x/sys/windows"
"reasonix/desktop/internal/winuninstall"
"reasonix/internal/installlayout"
"reasonix/internal/repair"
"reasonix/internal/platform/installlayout"
"reasonix/internal/platform/repair"
)
const parentExitTimeout = 2 * time.Minute
@@ -12,10 +12,10 @@ import (
"testing"
"time"
"reasonix/internal/installlayout"
"reasonix/internal/repair"
"reasonix/internal/platform/installlayout"
"reasonix/internal/platform/repair"
"reasonix/internal/tempdir"
"reasonix/internal/base/tempdir"
)
const testInstallerSHA256 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+2 -2
View File
@@ -8,8 +8,8 @@ import (
"sort"
"strings"
"reasonix/internal/repair"
"reasonix/internal/update"
"reasonix/internal/platform/repair"
"reasonix/internal/platform/update"
)
const maxWindowsPayloadMetadataSize = 64 << 10
@@ -7,9 +7,9 @@ import (
"strings"
"testing"
"reasonix/internal/repair"
"reasonix/internal/tempdir"
"reasonix/internal/update"
"reasonix/internal/base/tempdir"
"reasonix/internal/platform/repair"
"reasonix/internal/platform/update"
)
func TestLoadWindowsStagedReleaseUnitPreflightsAllMembersAndPublishesDesktopLast(t *testing.T) {
@@ -8,8 +8,8 @@ import (
"path/filepath"
"strings"
"reasonix/internal/installlayout"
"reasonix/internal/repair"
"reasonix/internal/platform/installlayout"
"reasonix/internal/platform/repair"
)
// activateVersionedWindowsFromStaging publishes the versioned-v1 layout from a
@@ -7,10 +7,10 @@ import (
"path/filepath"
"testing"
"reasonix/internal/installlayout"
"reasonix/internal/repair"
"reasonix/internal/platform/installlayout"
"reasonix/internal/platform/repair"
"reasonix/internal/tempdir"
"reasonix/internal/base/tempdir"
)
func TestPreferVersionedWindowsActivation(t *testing.T) {
+1 -1
View File
@@ -144,7 +144,7 @@ node perf/focus.mjs # 专注的守卫:拿走外围之后,退出时世
都读源码来对,不是对一份手抄清单。
- **词表不能悄悄缺。** 缺翻译时界面退回中文而不是空白,所以漏了不会自己暴露,
`perf/i18n.mjs` 是替代品:源码里每个 `t("…")` 的中文 key 都要在 `i18n/en.ts`
里有。这条对应 internal/i18n 的 catalog 测试,理由一样。
里有。这条对应 internal/base/i18n 的 catalog 测试,理由一样。
它读的是源码文本,所以**它自己也得说得出哪一行没读懂**。中文是合法的 JS
标识符,词表里 `"占用": "…"` 和 `占用: "…"` 两种写法都有,而它一度只认带引号
的那种——存储面板那六条于是被报成缺翻译,那六条其实一直都在。一条永远红的守卫
+1 -1
View File
@@ -1,6 +1,6 @@
// 词表守卫:源码里每个 t("…") 的中文 key,英文词表都要有;反过来词表里也不
// 该留下源码已经不用的条目。缺翻译时界面会退回中文而不是空白,正因如此漏了
// 不会自己暴露 —— 这个检查就是替代品,对应 internal/i18n 的 catalog 测试。
// 不会自己暴露 —— 这个检查就是替代品,对应 internal/base/i18n 的 catalog 测试。
import { readFileSync, readdirSync, statSync } from "node:fs";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";
+1 -1
View File
@@ -11,7 +11,7 @@ const DICTS: Record<Lang, Record<string, string>> = { zh: {}, en: EN };
// more than it returns, and this way the call site still reads as the sentence
// it renders — a translation that is missing falls back to the original rather
// than to a blank or a key. The catalogue's completeness is a test's job, the
// same way internal/i18n does it for the CLI.
// same way internal/base/i18n does it for the CLI.
let lang: Lang = "zh";
let dict = DICTS.zh;
+1 -1
View File
@@ -7,7 +7,7 @@ import { SsePort } from "./sse";
// and a missed round loses nothing, because the snapshot is the record.
const ASK_POLL_MS = 500;
// Must match operationHeader in internal/serve. The caller names the operation
// Must match operationHeader in internal/frontend/serve. The caller names the operation
// because the question can arrive before the response does.
function operationHeaders(operationId?: string): Record<string, string> {
return operationId ? { "x-reasonix-operation-id": operationId } : {};
+2 -2
View File
@@ -139,10 +139,10 @@ export class MockMcp extends MockProvider {
s.state = s.error ? "failed" : s.tools ? "standby" : "idle";
}
// A rough stand-in for internal/mcpsetup: enough shape for the confirmation
// A rough stand-in for internal/ext/mcpsetup: enough shape for the confirmation
// card to be developed against, not a second implementation of the grammar.
// A rough stand-in for internal/mcpsetup: enough shape for the confirmation
// A rough stand-in for internal/ext/mcpsetup: enough shape for the confirmation
// card to be developed against, not a second implementation of the grammar.
async parseMcp(input: string): Promise<McpDraft> {
const text = input.trim();
+4 -4
View File
@@ -39,7 +39,7 @@ export interface HistoryToolCall {
capabilityId?: string;
}
// GET /todos as internal/serve writes it: the canonical task list, the latest
// GET /todos as internal/frontend/serve writes it: the canonical task list, the latest
// todo_write merged with every complete_step advance. Deriving it from the
// transcript instead loses the advances and keeps the refused writes.
// A tab the agent's browser has open. target is the browser's own id for the
@@ -59,7 +59,7 @@ export interface HostTodo {
level?: number;
}
// GET /checkpoints as internal/serve writes it: the snapshot the kernel took
// GET /checkpoints as internal/frontend/serve writes it: the snapshot the kernel took
// before each turn's first write. prompt is the user's own text, with the
// compose prefixes already stripped kernel-side.
export interface Checkpoint {
@@ -140,7 +140,7 @@ export type Preset = "light" | "balanced" | "delivery";
// will honour rides on the request — see Approval.allowsSession/allowsPersist.
export type ApprovalVerdict = "once" | "session" | "always" | "deny";
// Shape of GET /status as internal/serve writes it. Anything the UI wants that
// Shape of GET /status as internal/frontend/serve writes it. Anything the UI wants that
// is not here has to be added on the Go side, not invented in the client.
// PlanAction is what a plan card can answer. The three are distinct kernel
// transitions, not an allow/deny pair: revising keeps planning, exiting leaves
@@ -251,7 +251,7 @@ export interface JobEntry {
startedAt: number;
}
// The UI depends on this and nothing else. SsePort talks to internal/serve;
// The UI depends on this and nothing else. SsePort talks to internal/frontend/serve;
// MockPort replays a fixture. Neither is allowed to leak transport details
// upward, which is what keeps the same UI usable in a browser and in a shell.
export interface SessionEntry {
+1 -1
View File
@@ -1,4 +1,4 @@
// Mirrors internal/tokencount.Text: Latin near four bytes per token, CJK near
// Mirrors internal/base/tokencount.Text: Latin near four bytes per token, CJK near
// one token per character. Used to size streamed deltas, which arrive as text
// and carry no count of their own — usage only lands at the end of a round.
export function estimateTokens(s: string): number {
+2 -2
View File
@@ -1,4 +1,4 @@
// Mirrors internal/eventwire. Field names and kind strings must match exactly;
// Mirrors internal/contract/eventwire. Field names and kind strings must match exactly;
// this file is the contract, not a convenience shape.
export type Kind =
@@ -509,7 +509,7 @@ export interface ReceiptGap {
}
// The run's execution graph, published as facts rather than drawn from id
// prefixes. Mirrors internal/agentgraph: a node named again updates the one
// prefixes. Mirrors internal/contract/agentgraph: a node named again updates the one
// already there, and an edge kind is what tells "waited for this" apart from
// "started from this answer".
export type GraphNodeKind = "group" | "worker" | "external";
+1 -1
View File
@@ -1,6 +1,6 @@
import type { ExecutionGraph, GraphDelta, GraphEdge, GraphNode } from "../port/wire";
// The run graph, folded the way internal/agentgraph folds it. The kernel is the
// The run graph, folded the way internal/contract/agentgraph folds it. The kernel is the
// only thing that knows a dependency from a delivered answer, so this reducer
// reads what it published rather than re-deriving structure from id prefixes —
// which is what the panel used to do, and why it could only ever draw a list.
Loaded 100 of 2952 files, more files were not shown because too many files have changed in this diff. Show more