Merge remote-tracking branch 'origin/master' into codex/pr-555-ci-fix

# Conflicts:
#	docs/config-catalog.i18n.yaml
#	docs/config-catalog.md
#	docs/config-catalog.zh.md
#	docs/module-graph.i18n.yaml
#	docs/module-graph.md
#	docs/module-graph.zh.md
#	examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl
#	packages/client/connection/src/client/fixture.ts
#	packages/host/apiproxy/src/api-proxy.ts
This commit is contained in:
creatixchu
2026-08-10 12:33:36 +08:00
331 changed files with 16610 additions and 557 deletions

View File

@@ -175,6 +175,22 @@ export class FakeApiClient implements IApiClient {
execute: (payload: unknown) => this.record('command.execute', payload, this.onCommandExecute(payload)),
}
readonly agentPresets: IApiClient['agentPresets'] = {
list: (payload: unknown) => this.record('agentPreset.list', payload, Promise.resolve(ok({ presets: [], authorable: false, hasDocument: false }))),
select: (payload: { agentPreset: string }) =>
this.record('agentPreset.select', payload, Promise.resolve(ok({ agentPreset: payload.agentPreset }))),
read: (payload: { agentPreset: string }) =>
this.record('agentPreset.read', payload, Promise.resolve(ok({
agentPreset: payload.agentPreset, trust: 'user' as const, content: '',
}))),
copy: (payload: { agentPreset: string }) =>
this.record('agentPreset.copy', payload, Promise.resolve(ok({ agentPreset: payload.agentPreset }))),
openDocument: (payload: { agentPreset: string }) =>
this.record('agentPreset.openDocument', payload, Promise.resolve(ok({ opened: true as const }))),
remove: (payload: { agentPreset: string }) =>
this.record('agentPreset.remove', payload, Promise.resolve(ok({}))),
}
readonly skills: IApiClient['skills'] = {
list: (payload: unknown) => this.record('skill.list', payload, this.onSkillList(payload)),
}

View File

@@ -173,6 +173,10 @@ describe('connection node half', () => {
'settings.describe', 'settings.openDocument', 'settings.update', 'settings.replace', 'settings.mutate',
'credentials.describe', 'credentials.set', 'credentials.unset',
'llm.discoverModels',
// A composition names the plugins a session runs: reading one is
// reconnaissance, and copy/remove/openDocument manage the roster and
// drive the host desktop.
'agentPreset.read', 'agentPreset.copy', 'agentPreset.openDocument', 'agentPreset.remove',
]) {
const denied = fakeResponse()
await routes[0]!.handler(
@@ -466,13 +470,19 @@ describe('connection node half over a real HTTP server', () => {
// Carries a draft credential and turns the host into a fetcher for a
// URL the caller picked: an anonymous LAN caller must not reach it.
'llm.discoverModels',
'agentPreset.read', 'agentPreset.copy', 'agentPreset.openDocument', 'agentPreset.remove',
]) {
expect([method, await call(port, method, 'harness.example')]).toEqual([method, 403])
}
// The model catalog stays reachable for the same authority: a LAN
// client's model picker needs it, and it carries no key or endpoint
// state (404 is the empty proxy's carrier answer — the fence passed).
for (const method of ['llm.providers', 'llm.models']) {
// `agentPreset.list` joins the model catalog for the same reason: ids and
// trust only, and a LAN client's preset picker needs it. `select` is
// reachable too: `session.create` already takes an `agentPreset`, and the
// deployment's own default already carries bash, so pinning the switch
// would be a fence beside an open gate.
for (const method of ['llm.providers', 'llm.models', 'agentPreset.list', 'agentPreset.select']) {
expect([method, await call(port, method, 'harness.example')]).toEqual([method, 404])
}
// Loopback reaches everything, configuration included.