Merge remote-tracking branch 'origin/master' into xtr/react-loop-simplification

# Conflicts:
#	.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.i18n.yaml
#	examples/acp-agent/tests/snapshots/fs-glob-sampling/session.jsonl
#	packages/ui/tui/README.i18n.yaml
#	packages/ui/tui/src/components/dialogs.ts
#	packages/ui/tui/tests/tui.spec.ts
This commit is contained in:
_Kerman
2026-08-04 10:52:45 +08:00
74 changed files with 2492 additions and 1148 deletions
+44 -8
View File
@@ -1,6 +1,6 @@
import { fileURLToPath } from 'node:url'
import { readFileSync } from 'node:fs'
import { mkdir, writeFile } from 'node:fs/promises'
import { mkdir, utimes, writeFile } from 'node:fs/promises'
import { dirname, join } from 'node:path'
import { homedir } from 'node:os'
import { expect, it } from 'vitest'
@@ -47,7 +47,6 @@ const SUBAGENT_DURABILITY_FAILURE_CONFIG = fileURLToPath(
const LSP_CONFIG = fileURLToPath(new URL('./lsp.cordis.yml', import.meta.url))
const WEB_CONFIG = fileURLToPath(new URL('../web.cordis.yml', import.meta.url))
const FS_SEARCH_CONFIG = fileURLToPath(new URL('./fs-search.cordis.yml', import.meta.url))
const FS_SEARCH_BIN = fileURLToPath(new URL('./fixtures/fs-search-bin', import.meta.url))
const SNAPSHOTS_DIR = join(dirname(fileURLToPath(import.meta.url)), 'snapshots')
const PACKED_CHUNKS_SOURCE = 'hook-cc-pretool-deny'
@@ -60,6 +59,33 @@ async function prepareDelimiterPathWorkspace(cwd: string): Promise<void> {
])
}
/**
* Seed the over-cap glob fixture: eight files under `tree/` with fixed mtimes,
* so the packaged ripgrep's `--sort=modified` order is deterministic — three
* files under `archive/`, one each under `docs/`, `src/`, and `test/`, plus
* two flat files (six top-level entries). Scoping the search to `tree/` keeps
* the harness's own session artifacts out of the listing.
*/
async function prepareFsSearchWorkspace(cwd: string): Promise<void> {
const tree = join(cwd, 'tree')
const files: Array<[relative: string, mtime: Date]> = [
[join('archive', 'a.ts'), new Date(2000, 0, 1, 0, 0, 0, 1)],
[join('archive', 'b.ts'), new Date(2000, 0, 1, 0, 0, 0, 2)],
[join('archive', 'c.ts'), new Date(2000, 0, 1, 0, 0, 0, 3)],
[join('docs', 'guide.md'), new Date(2000, 0, 1, 0, 0, 0, 4)],
[join('src', 'index.ts'), new Date(2000, 0, 1, 0, 0, 0, 5)],
[join('test', 'spec.ts'), new Date(2000, 0, 1, 0, 0, 0, 6)],
['top.txt', new Date(2000, 0, 1, 0, 0, 0, 7)],
['notes.md', new Date(2000, 0, 1, 0, 0, 0, 8)],
]
for (const [relative, mtime] of files) {
const target = join(tree, relative)
await mkdir(dirname(target), { recursive: true })
await writeFile(target, 'fixture\n')
await utimes(target, mtime, mtime)
}
}
// FIXME: Migrate backend-oriented scenarios to the headless stream-json suite;
// this ACP suite should eventually retain only automation-protocol contracts.
@@ -153,18 +179,28 @@ const SCENARIOS: Scenario[] = [
hasModelTurn: true,
recorded: true,
},
// The real Loader/app/bash path executes a deterministic rg stand-in at the
// external-process seam, pinning over-cap glob sampling without depending on
// a host-installed ripgrep binary.
// The real Loader/app/subprocess path executes the PACKAGED ripgrep binary
// against a prepared workspace whose fixed mtimes pin the
// `--sort=modified` order, pinning over-cap glob sampling without depending
// on a host-installed ripgrep binary or a PATH stand-in. POSIX-only because
// the displayed paths carry `/` separators the session-log comparison
// cannot normalize. Recorded (not authored): the assistant turn is a real
// model transcript; re-record with `test:snapshot:record -t fs-glob-sampling`
// and then `migrate:packed-session-fixtures`, which canonicalizes the live
// log's eager-drain-packed rows into the maximal-run layout replay produces.
// The recorded fixture's `request/header` config and `request/context` are
// normalized to the replay-produced minimal shape (the live adapter logs
// model capabilities like maxTokens/reasoningEffort that llm-replay has no
// data for), and its tool-result paths are canonicalized to `/` separators.
{
name: 'fs-glob-sampling',
hasModelTurn: true,
recorded: false,
recorded: true,
posixOnly: true,
pinsHeader: true,
headerClass: 'fs-search',
configPath: FS_SEARCH_CONFIG,
env: { PATH: `${FS_SEARCH_BIN}:${process.env.PATH ?? ''}` },
posixOnly: true,
prepareWorkspace: prepareFsSearchWorkspace,
},
{ name: 'fs-read', hasModelTurn: true, recorded: true },
{ name: 'fs-write', hasModelTurn: true, recorded: true },