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

View File

@@ -58,25 +58,34 @@
# ── TUI-only rows ───────────────────────────────────────────────────────────
- insert:
# Relational runtime checks over the authoritative event streams; each
# companion registers the assertions its own package owns.
- id: invariants
name: '@deepseek-ai/dsh-invariants'
- id: session-invariant
name: '@deepseek-ai/dsh-session/invariant'
- id: agent-invariant
name: '@deepseek-ai/dsh-agent/invariant'
- id: scope-invariant
name: '@deepseek-ai/dsh-scope/invariant'
- id: agent-loop-invariant
name: '@deepseek-ai/dsh-agent-loop/invariant'
# The derived query index behind `/resume`. The launcher provides a unique
# process-local path because this SQLite backend has one writer owner; the
# project-local fallback applies when no launcher sets the typed slot.
- id: session-reference
name: '@deepseek-ai/dsh-session-reference'
# The projection registry plus its durable checkpoint cache (over the same
# storage root the web surface uses): `/resume` reads titles from the
# zero-I/O checkpoint row or a tail-only cold read instead of scanning
# whole logs, and checkpoints written by either surface serve both.
- id: session-projection
name: '@deepseek-ai/dsh-session-projection'
- id: storage
name: '@deepseek-ai/dsh-storage'
- id: storage-json
name: '@deepseek-ai/dsh-storage-json'
config:
root: !!js dshHomePath('storages')
- id: storage-domain
name: '@deepseek-ai/dsh-storage-domain'
config:
backend: json
- id: session-projection-cache
name: '@deepseek-ai/dsh-session-projection-cache'
config:
writeEveryEvents: 200
writeIntervalMs: 5000
# Terminal-multiplexer context, mounted only where a terminal exists.
- id: tmux-context
name: '@deepseek-ai/dsh-tmux-context'

View File

@@ -65,7 +65,6 @@
"@deepseek-ai/dsh-host-directory-picker-browse": "workspace:^",
"@deepseek-ai/dsh-host-directory-picker-native": "workspace:^",
"@deepseek-ai/dsh-host-webserver": "workspace:^",
"@deepseek-ai/dsh-invariants": "workspace:^",
"@deepseek-ai/dsh-llm": "workspace:^",
"@deepseek-ai/dsh-llm-deepseek": "workspace:^",
"@deepseek-ai/dsh-llm-pi-ai": "workspace:^",

View File

@@ -94,6 +94,8 @@ describe.skipIf(!existsSync(dshBin))('dsh BUILT bin (node lib/bin.js, no tsx)',
expect(stdout).toContain('model: deepseek-v4-pro')
expect(stdout).toContain('cwd: !!js process.cwd()')
expect(stdout).toContain("name: '@deepseek-ai/dsh-tui'")
expect(stdout).not.toMatch(/name: ['"]@deepseek-ai\/dsh-invariants['"]/)
expect(stdout).not.toMatch(/name: ['"]@deepseek-ai\/dsh-[^'"]+\/invariant['"]/)
expect(stdout).toContain([
'- id: tool-web',
" name: '@deepseek-ai/dsh-tool-web'",
@@ -140,6 +142,8 @@ describe.skipIf(!existsSync(dshBin))('dsh BUILT bin (node lib/bin.js, no tsx)',
expect(code).toBe(0)
expect(stdout).toContain("name: '@deepseek-ai/dsh-host-webserver'")
expect(stdout).not.toContain("name: '@deepseek-ai/dsh-tui'")
expect(stdout).not.toMatch(/name: ['"]@deepseek-ai\/dsh-invariants['"]/)
expect(stdout).not.toMatch(/name: ['"]@deepseek-ai\/dsh-[^'"]+\/invariant['"]/)
}, 30_000)
})
})

View File

@@ -52,10 +52,10 @@ const EXPECTED_TUI_TOOLS = [
]
/**
* `glob` and `grep` come from `dsh-tool-fs-search`, which probes `command -v rg`
* through the mounted bash executor at load and registers neither tool when
* ripgrep is absent. That is a host dependency, not a composition decision, so the
* pair is asserted separately — present together or absent together.
* `glob` and `grep` come from `dsh-tool-fs-search`, which spawns the PACKAGED
* ripgrep binary (`@vscode/ripgrep`) through the subprocess seam, so the pair
* is always present on every host — asserted as fixed members, not a host
* dependency.
*/
const RIPGREP_TOOLS = ['glob', 'grep']
@@ -123,7 +123,9 @@ describe('shipped dsh composition (real Loader tree in a PTY)', () => {
expect(output).toContain(COMPOSITION_REPLY_TEXT)
expect(output).toContain(PERMISSION_SUMMARY)
expect(observed?.names.filter(name => !RIPGREP_TOOLS.includes(name))).toEqual(EXPECTED_TUI_TOOLS)
expect([[], RIPGREP_TOOLS]).toContainEqual(observed?.names.filter(name => RIPGREP_TOOLS.includes(name)))
// The packaged ripgrep binary ships with the dependency, so the pair is a
// fixed roster member on every host.
expect(observed?.names.filter(name => RIPGREP_TOOLS.includes(name))).toEqual(RIPGREP_TOOLS)
expect(observed?.bashArguments).toHaveProperty('sandbox_permissions')
expect(observed?.bashArguments).toHaveProperty('justification')
expect(observed?.permissionEvents).toEqual([