agent-trellis 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/mcpPlan.d.ts +5 -0
- package/dist/adapters/mcpPlan.js +7 -1
- package/dist/cli.js +11 -5
- package/dist/commands/mcp.d.ts +41 -2
- package/dist/commands/mcp.js +111 -14
- package/dist/commands/mcpAuth.js +28 -0
- package/dist/core/canonical.d.ts +15 -12
- package/dist/core/canonical.js +86 -18
- package/dist/core/types.d.ts +28 -2
- package/dist/core/types.js +19 -0
- package/dist/lib/oauth/flow.d.ts +13 -0
- package/dist/lib/oauth/flow.js +48 -3
- package/dist/lib/secretEnv.d.ts +5 -0
- package/dist/lib/secretEnv.js +8 -0
- package/dist/pi-bridge/bundle.js +738 -680
- package/dist/pi-bridge/index.js +2 -2
- package/docs/architecture.md +19 -0
- package/docs/mcp-oauth-matrix.md +140 -0
- package/docs/research.md +11 -0
- package/package.json +4 -2
- package/schema/servers.example.yaml +18 -0
- package/docs/video/README.md +0 -76
- package/docs/video/build/audio/01-opening.aiff +0 -0
- package/docs/video/build/audio/01-opening.mp3 +0 -0
- package/docs/video/build/audio/02-pain.aiff +0 -0
- package/docs/video/build/audio/02-pain.mp3 +0 -0
- package/docs/video/build/audio/03-solution.aiff +0 -0
- package/docs/video/build/audio/03-solution.mp3 +0 -0
- package/docs/video/build/audio/04-install.aiff +0 -0
- package/docs/video/build/audio/04-install.mp3 +0 -0
- package/docs/video/build/audio/04-setup.mp3 +0 -0
- package/docs/video/build/audio/05-dryrun.mp3 +0 -0
- package/docs/video/build/audio/05-init.aiff +0 -0
- package/docs/video/build/audio/05-init.mp3 +0 -0
- package/docs/video/build/audio/05-interactive.mp3 +0 -0
- package/docs/video/build/audio/06-dryrun.aiff +0 -0
- package/docs/video/build/audio/06-dryrun.mp3 +0 -0
- package/docs/video/build/audio/06-onboard.mp3 +0 -0
- package/docs/video/build/audio/06-run.mp3 +0 -0
- package/docs/video/build/audio/07-onboard.aiff +0 -0
- package/docs/video/build/audio/07-onboard.mp3 +0 -0
- package/docs/video/build/audio/07-verify.mp3 +0 -0
- package/docs/video/build/audio/08-closing.mp3 +0 -0
- package/docs/video/build/audio/08-doctor.aiff +0 -0
- package/docs/video/build/audio/08-doctor.mp3 +0 -0
- package/docs/video/build/audio/09-rollback.aiff +0 -0
- package/docs/video/build/audio/09-rollback.mp3 +0 -0
- package/docs/video/build/audio/10-principles.aiff +0 -0
- package/docs/video/build/audio/10-principles.mp3 +0 -0
- package/docs/video/build/audio/11-closing.aiff +0 -0
- package/docs/video/build/audio/11-closing.mp3 +0 -0
- package/docs/video/build/frames/01-opening-0.png +0 -0
- package/docs/video/build/frames/02-pain-1.png +0 -0
- package/docs/video/build/frames/02-pain-2.png +0 -0
- package/docs/video/build/frames/03-solution-3.png +0 -0
- package/docs/video/build/frames/04-install-4.png +0 -0
- package/docs/video/build/frames/04-setup-4.png +0 -0
- package/docs/video/build/frames/04-setup-5.png +0 -0
- package/docs/video/build/frames/05-dryrun-6.png +0 -0
- package/docs/video/build/frames/05-init-5.png +0 -0
- package/docs/video/build/frames/05-interactive-5.png +0 -0
- package/docs/video/build/frames/05-interactive-6.png +0 -0
- package/docs/video/build/frames/06-dryrun-6.png +0 -0
- package/docs/video/build/frames/06-dryrun-7.png +0 -0
- package/docs/video/build/frames/06-onboard-7.png +0 -0
- package/docs/video/build/frames/06-onboard-8.png +0 -0
- package/docs/video/build/frames/06-run-7.png +0 -0
- package/docs/video/build/frames/06-run-8.png +0 -0
- package/docs/video/build/frames/07-onboard-10.png +0 -0
- package/docs/video/build/frames/07-onboard-7.png +0 -0
- package/docs/video/build/frames/07-onboard-8.png +0 -0
- package/docs/video/build/frames/07-onboard-9.png +0 -0
- package/docs/video/build/frames/07-verify-10.png +0 -0
- package/docs/video/build/frames/07-verify-8.png +0 -0
- package/docs/video/build/frames/07-verify-9.png +0 -0
- package/docs/video/build/frames/08-closing-10.png +0 -0
- package/docs/video/build/frames/08-closing-11.png +0 -0
- package/docs/video/build/frames/08-doctor-11.png +0 -0
- package/docs/video/build/frames/08-doctor-9.png +0 -0
- package/docs/video/build/frames/09-rollback-10.png +0 -0
- package/docs/video/build/frames/09-rollback-12.png +0 -0
- package/docs/video/build/frames/10-principles-11.png +0 -0
- package/docs/video/build/frames/10-principles-13.png +0 -0
- package/docs/video/build/frames/11-closing-12.png +0 -0
- package/docs/video/build/frames/11-closing-14.png +0 -0
- package/docs/video/build/segments/01-opening.mp4 +0 -0
- package/docs/video/build/segments/01-opening.txt +0 -3
- package/docs/video/build/segments/02-pain.mp4 +0 -0
- package/docs/video/build/segments/02-pain.txt +0 -5
- package/docs/video/build/segments/03-solution.mp4 +0 -0
- package/docs/video/build/segments/03-solution.txt +0 -3
- package/docs/video/build/segments/04-install.mp4 +0 -0
- package/docs/video/build/segments/04-install.txt +0 -3
- package/docs/video/build/segments/04-setup.mp4 +0 -0
- package/docs/video/build/segments/04-setup.txt +0 -3
- package/docs/video/build/segments/05-dryrun.mp4 +0 -0
- package/docs/video/build/segments/05-dryrun.txt +0 -3
- package/docs/video/build/segments/05-init.mp4 +0 -0
- package/docs/video/build/segments/05-init.txt +0 -3
- package/docs/video/build/segments/05-interactive.mp4 +0 -0
- package/docs/video/build/segments/05-interactive.txt +0 -5
- package/docs/video/build/segments/06-dryrun.mp4 +0 -0
- package/docs/video/build/segments/06-dryrun.txt +0 -3
- package/docs/video/build/segments/06-onboard.mp4 +0 -0
- package/docs/video/build/segments/06-onboard.txt +0 -5
- package/docs/video/build/segments/06-run.mp4 +0 -0
- package/docs/video/build/segments/06-run.txt +0 -3
- package/docs/video/build/segments/07-onboard.mp4 +0 -0
- package/docs/video/build/segments/07-onboard.txt +0 -5
- package/docs/video/build/segments/07-verify.mp4 +0 -0
- package/docs/video/build/segments/07-verify.txt +0 -5
- package/docs/video/build/segments/08-closing.mp4 +0 -0
- package/docs/video/build/segments/08-closing.txt +0 -3
- package/docs/video/build/segments/08-doctor.mp4 +0 -0
- package/docs/video/build/segments/08-doctor.txt +0 -3
- package/docs/video/build/segments/09-rollback.mp4 +0 -0
- package/docs/video/build/segments/09-rollback.txt +0 -3
- package/docs/video/build/segments/10-principles.mp4 +0 -0
- package/docs/video/build/segments/10-principles.txt +0 -3
- package/docs/video/build/segments/11-closing.mp4 +0 -0
- package/docs/video/build/segments/11-closing.txt +0 -3
- package/docs/video/build/segments/final.txt +0 -8
- package/docs/video/build-ai/audio/01-hook.mp3 +0 -0
- package/docs/video/build-ai/audio/02-pain.mp3 +0 -0
- package/docs/video/build-ai/audio/03-solution.mp3 +0 -0
- package/docs/video/build-ai/audio/04-how.mp3 +0 -0
- package/docs/video/build-ai/audio/05-safe.mp3 +0 -0
- package/docs/video/build-ai/audio/06-closing.mp3 +0 -0
- package/docs/video/build-ai/clips/01-hook.mp4 +0 -0
- package/docs/video/build-ai/clips/02-pain.mp4 +0 -0
- package/docs/video/build-ai/clips/03-solution.mp4 +0 -0
- package/docs/video/build-ai/clips/04-how.mp4 +0 -0
- package/docs/video/build-ai/clips/05-safe.mp4 +0 -0
- package/docs/video/build-ai/clips/06-closing.mp4 +0 -0
- package/docs/video/build-ai/first-frame-02-pain.png +0 -0
- package/docs/video/build-ai/first-frame-03-solution.png +0 -0
- package/docs/video/build-ai/first-frame-04-how.png +0 -0
- package/docs/video/build-ai/first-frame-05-safe.png +0 -0
- package/docs/video/build-ai/segments/01-hook.caption.txt +0 -2
- package/docs/video/build-ai/segments/01-hook.mp4 +0 -0
- package/docs/video/build-ai/segments/02-pain.mp4 +0 -0
- package/docs/video/build-ai/segments/03-solution.mp4 +0 -0
- package/docs/video/build-ai/segments/04-how.mp4 +0 -0
- package/docs/video/build-ai/segments/05-safe.mp4 +0 -0
- package/docs/video/build-ai/segments/06-closing.mp4 +0 -0
- package/docs/video/build-ai/segments/cap-01-hook.png +0 -0
- package/docs/video/build-ai/segments/cap-02-pain.png +0 -0
- package/docs/video/build-ai/segments/cap-03-solution.png +0 -0
- package/docs/video/build-ai/segments/cap-04-how.png +0 -0
- package/docs/video/build-ai/segments/cap-05-safe.png +0 -0
- package/docs/video/build-ai/segments/cap-06-closing.png +0 -0
- package/docs/video/build-ai/segments/final.txt +0 -6
- package/docs/video/build-posters/audio/01-hook.mp3 +0 -0
- package/docs/video/build-posters/audio/02-pain.mp3 +0 -0
- package/docs/video/build-posters/audio/03-solution.mp3 +0 -0
- package/docs/video/build-posters/audio/04-how.mp3 +0 -0
- package/docs/video/build-posters/audio/05-safe.mp3 +0 -0
- package/docs/video/build-posters/audio/06-closing.mp3 +0 -0
- package/docs/video/build-posters/cap-01-hook.png +0 -0
- package/docs/video/build-posters/cap-02-pain.png +0 -0
- package/docs/video/build-posters/cap-03-solution.png +0 -0
- package/docs/video/build-posters/cap-04-how.png +0 -0
- package/docs/video/build-posters/cap-05-safe.png +0 -0
- package/docs/video/build-posters/cap-06-closing.png +0 -0
- package/docs/video/build-posters/card-01-hook.png +0 -0
- package/docs/video/build-posters/card-06-closing.png +0 -0
- package/docs/video/build-posters/segments/01-hook.mp4 +0 -0
- package/docs/video/build-posters/segments/02-pain.mp4 +0 -0
- package/docs/video/build-posters/segments/03-solution.mp4 +0 -0
- package/docs/video/build-posters/segments/04-how.mp4 +0 -0
- package/docs/video/build-posters/segments/05-safe.mp4 +0 -0
- package/docs/video/build-posters/segments/06-closing.mp4 +0 -0
- package/docs/video/build-posters/segments/final.txt +0 -6
- package/docs/video/generate-video-ai.mjs +0 -334
- package/docs/video/generate-video-posters.mjs +0 -204
- package/docs/video/generate-video.mjs +0 -426
- package/docs/video/outline.zh-CN.md +0 -102
- package/docs/video/trellis-demo-video-ai.mp4 +0 -0
- package/docs/video/trellis-demo-video.mp4 +0 -0
- package/docs/video/voiceover.zh-CN.md +0 -49
package/dist/pi-bridge/index.js
CHANGED
|
@@ -17,7 +17,7 @@ import { resolveMcpPlan } from "../adapters/mcpPlan.js";
|
|
|
17
17
|
import { connectServer, withTimeout, DEFAULT_CONNECT_TIMEOUT_MS } from "../lib/mcpConnect.js";
|
|
18
18
|
import { McpToolRegistry } from "../lib/mcpToolRegistry.js";
|
|
19
19
|
import { withOAuthHeader } from "../lib/gatewayBackend.js";
|
|
20
|
-
import { ALL_AGENTS } from "../core/types.js";
|
|
20
|
+
import { ALL_AGENTS, isOAuthAuth } from "../core/types.js";
|
|
21
21
|
import { toParametersSchema, toPiContent } from "./schemaTranslate.js";
|
|
22
22
|
/** Re-exported so `trellis-mcp-connect-timeout`'s existing test keeps
|
|
23
23
|
* importing it from the module it was written against — proving the
|
|
@@ -75,7 +75,7 @@ export default async function trellisMcpBridge(pi, homeDir = homedir(), connectT
|
|
|
75
75
|
const discovered = await Promise.all(desired.map(async ({ name, def }) => {
|
|
76
76
|
let client;
|
|
77
77
|
try {
|
|
78
|
-
const effectiveDef = def.auth
|
|
78
|
+
const effectiveDef = isOAuthAuth(def.auth) && def.url
|
|
79
79
|
? await withOAuthHeader(name, def, homeDir)
|
|
80
80
|
: def;
|
|
81
81
|
client = await connectServer(effectiveDef, canonical.secretsPolicy, connectTimeoutMs, CLIENT_INFO);
|
package/docs/architecture.md
CHANGED
|
@@ -266,6 +266,25 @@ flow for Claude Code/Codex/Kiro; Pi's bridge is the client for its direct OAuth
|
|
|
266
266
|
connection and may use Trellis's own OAuth store. Trellis never infers this
|
|
267
267
|
classification from a URL or a transient 401.
|
|
268
268
|
|
|
269
|
+
The classification optionally carries pre-registered client metadata, for
|
|
270
|
+
providers that refuse Dynamic Client Registration and require an allowlisted
|
|
271
|
+
client instead:
|
|
272
|
+
|
|
273
|
+
```yaml
|
|
274
|
+
auth:
|
|
275
|
+
kind: oauth
|
|
276
|
+
client_id: "<provider-published-id>" # public by design, literal
|
|
277
|
+
client_secret_env: PROVIDER_CLIENT_SECRET # a NAME, resolved via secrets.policy.yaml
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
`client_id` wins over DCR when present; DCR stays the fallback when it is
|
|
281
|
+
absent. There is deliberately no literal secret field — a secret enters only
|
|
282
|
+
as a variable name, the same `env`-style discipline everything else follows.
|
|
283
|
+
See docs/mcp-oauth-matrix.md for which providers are open to registration and
|
|
284
|
+
which are not, and for the distribution rule: examples, docs, and seed data
|
|
285
|
+
ship placeholders only, and only provider-**published** identifiers may ever
|
|
286
|
+
be pre-filled.
|
|
287
|
+
|
|
269
288
|
Trellis still implements the client half itself — discovery (RFC 8414 /
|
|
270
289
|
RFC 9728), dynamic client registration (RFC 7591), authorization code with
|
|
271
290
|
PKCE S256 (RFC 7636), and the refresh grant — in `src/lib/oauth/`, but that
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Remote MCP providers — how OAuth identity works, and where Trellis can help
|
|
2
|
+
|
|
3
|
+
`trellis mcp auth <name>` can only complete an authorization-code grant if it
|
|
4
|
+
is allowed to *have* a client identity. Whether it may is entirely the
|
|
5
|
+
provider's decision, and that decision splits remote MCP providers into two
|
|
6
|
+
families. This page records which family each known provider is in, what
|
|
7
|
+
evidence that rests on, and what Trellis does in each case.
|
|
8
|
+
|
|
9
|
+
Read alongside docs/architecture.md §"Static header auth vs. real OAuth",
|
|
10
|
+
which covers the *other* shape — a long-lived bearer token or API key in a
|
|
11
|
+
`headers` field — and why Trellis builds for both.
|
|
12
|
+
|
|
13
|
+
## The two families
|
|
14
|
+
|
|
15
|
+
**DCR-open.** The provider implements RFC 7591 Dynamic Client Registration.
|
|
16
|
+
Trellis POSTs its own metadata, receives a `client_id`, and holds its own
|
|
17
|
+
identity per installation. Nothing a user has to supply; nothing Trellis has
|
|
18
|
+
to distribute. This already works: it is what `trellis mcp auth` has done
|
|
19
|
+
since `trellis-mcp-gateway-hosting`.
|
|
20
|
+
|
|
21
|
+
**Allowlist.** The provider refuses registration — either by not advertising a
|
|
22
|
+
`registration_endpoint`, or by answering it with `unauthorized_client` — and
|
|
23
|
+
requires clients to be pre-registered with the provider. There is no
|
|
24
|
+
self-service path: the user obtains a `client_id` out of band and supplies it.
|
|
25
|
+
That is what the `auth.client_id` / `auth.client_secret_env` fields exist for
|
|
26
|
+
(trellis-mcp-oauth-static-client design.md D1–D3).
|
|
27
|
+
|
|
28
|
+
The 2026-07-28 MCP authorization spec moved in the allowlist direction,
|
|
29
|
+
downgrading Dynamic Client Registration from a MUST to a MAY in favour of
|
|
30
|
+
pre-registration. Expect the second family to grow; the mechanism, not the
|
|
31
|
+
per-provider list, is what Trellis commits to.
|
|
32
|
+
|
|
33
|
+
## Matrix
|
|
34
|
+
|
|
35
|
+
| Provider | Family | What identifies the client | Evidence | Confidence |
|
|
36
|
+
|---|---|---|---|---|
|
|
37
|
+
| Sentry | DCR-open | `client_id` from DCR | Local successful grant against the real server; secondary sources describing its DCR endpoint | Medium — see the note below |
|
|
38
|
+
| Supabase | DCR-open | `client_id` from DCR | Same | Medium |
|
|
39
|
+
| Morphix | DCR-open | `client_id` from DCR | Same | Medium |
|
|
40
|
+
| GitHub | DCR-open | `client_id` from DCR | Same | Medium |
|
|
41
|
+
| Notion | DCR-open | `client_id` from DCR | Same | Medium |
|
|
42
|
+
| Linear | DCR-open | `client_id` from DCR | Same | Medium |
|
|
43
|
+
| Cloudflare | DCR-open | `client_id` from DCR | Same | Medium |
|
|
44
|
+
| Figma | Allowlist | Provider-published `client_id`, supplied by the user | Registration refused with `unauthorized_client` — observed directly, and the reason this change exists | High |
|
|
45
|
+
|
|
46
|
+
**On confidence.** "High" means the behavior was observed directly against the
|
|
47
|
+
live provider and the failure (or success) is reproducible from this
|
|
48
|
+
repository's own test fixtures. "Medium" means the status rests on a working
|
|
49
|
+
local grant plus secondary sources rather than a first-party policy statement —
|
|
50
|
+
the *observed* behavior is solid, but a provider is free to change its
|
|
51
|
+
registration policy at any time, and none of these have published a
|
|
52
|
+
contractual commitment either way. Sentry is explicitly in this bucket
|
|
53
|
+
(trellis-mcp-oauth-static-client design.md D6): the local grant proves
|
|
54
|
+
registration works today, not that it will next quarter.
|
|
55
|
+
|
|
56
|
+
Treat the whole table as a snapshot of observed behavior, not as provider
|
|
57
|
+
policy. `trellis mcp auth` reports the actual failure when a row goes stale —
|
|
58
|
+
see "When a provider refuses" below.
|
|
59
|
+
|
|
60
|
+
## What actually identifies a client
|
|
61
|
+
|
|
62
|
+
There is no magic header and no provider-specific handshake. Any OAuth 2.0
|
|
63
|
+
authorization server that speaks the MCP authorization profile identifies a
|
|
64
|
+
client by a combination of:
|
|
65
|
+
|
|
66
|
+
- **`client_id`** — the identity itself. Public by design for a public client:
|
|
67
|
+
it travels in the browser URL on every authorization (`?client_id=...`), so
|
|
68
|
+
it is visible to the user, their browser history, and any proxy in between.
|
|
69
|
+
Its security rests on the *other* factors here, never on its secrecy.
|
|
70
|
+
- **Exact `redirect_uri` match** — registered with the client and required to
|
|
71
|
+
match byte-for-byte. This is why Trellis's loopback callback is what it is:
|
|
72
|
+
`http://127.0.0.1:<port>/callback`, with the port chosen by the OS at bind
|
|
73
|
+
time. A pre-registered client whose provider pins one specific port is the
|
|
74
|
+
one case where a fixed `callbackPort` is needed.
|
|
75
|
+
- **PKCE (RFC 7636, `S256`)** — the proof that whoever redeems the code is
|
|
76
|
+
whoever started the flow. The verifier never travels through the browser;
|
|
77
|
+
only its SHA-256 challenge does. Trellis's fake Authorization Server in the
|
|
78
|
+
test suite *enforces* this rather than rubber-stamping it, so the tests
|
|
79
|
+
cannot pass for a client that gets PKCE wrong.
|
|
80
|
+
- **`resource` parameter** — binds the grant to the MCP server it was issued
|
|
81
|
+
for, so a token minted for one server is not replayable against another.
|
|
82
|
+
|
|
83
|
+
Nothing in that list is a secret for a public client, which is exactly why
|
|
84
|
+
`client_id` is a plain literal in canonical YAML and `client_secret_env` — the
|
|
85
|
+
one field that *is* a credential — is a variable NAME resolved through
|
|
86
|
+
`secrets.policy.yaml` and never a value (design.md D2).
|
|
87
|
+
|
|
88
|
+
## When a provider refuses
|
|
89
|
+
|
|
90
|
+
`trellis mcp auth <name>` tries pre-registered metadata first, then DCR. When
|
|
91
|
+
both are unavailable it fails with the remediation rather than a bare status
|
|
92
|
+
code:
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
"figma": dynamic client registration was refused (unauthorized_client) —
|
|
96
|
+
register a client with the provider and set auth.client_id (plus
|
|
97
|
+
auth.client_secret_env if the provider requires a secret) under this server in
|
|
98
|
+
~/.trellis/mcp/servers.yaml
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The fix is then two commands:
|
|
102
|
+
|
|
103
|
+
```sh
|
|
104
|
+
trellis mcp set figma --auth oauth --client-id <provider-published-id>
|
|
105
|
+
trellis mcp auth figma
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The id comes from the provider. Trellis does not ship one, look one up for
|
|
109
|
+
you, or read another client's stored credentials to borrow an identity —
|
|
110
|
+
that last option is rejected structurally, not just by policy (design.md D5:
|
|
111
|
+
borrowing a refresh token makes both clients fight over rotation, and reading
|
|
112
|
+
another tool's credential store would mean decrypting files Trellis does not
|
|
113
|
+
own).
|
|
114
|
+
|
|
115
|
+
## Distribution boundary
|
|
116
|
+
|
|
117
|
+
Trellis is open source. What it distributes is a mechanism — the schema field,
|
|
118
|
+
the flow, the tests. It does not distribute an identity.
|
|
119
|
+
|
|
120
|
+
A user who obtains a `client_id` and pastes it into their own
|
|
121
|
+
`~/.trellis/mcp/servers.yaml` is making their own decision under the provider's
|
|
122
|
+
terms, in the same position as anyone running `mcp-remote
|
|
123
|
+
--static-oauth-client-info`. Trellis shipping that same id in
|
|
124
|
+
`schema/servers.example.yaml`, in this page, or in seed data would instead make
|
|
125
|
+
the project itself the distributor of a whitelist-bypass tool. So:
|
|
126
|
+
|
|
127
|
+
- Examples and docs use placeholders only — see the commented block in
|
|
128
|
+
`schema/servers.example.yaml`.
|
|
129
|
+
- Only provider-**published** identifiers may ever be pre-filled. None exist
|
|
130
|
+
today, so nothing is pre-filled.
|
|
131
|
+
- A literal that matches `reject_patterns` is refused at load and at write, so
|
|
132
|
+
a pasted credential cannot quietly become part of the canonical source.
|
|
133
|
+
|
|
134
|
+
## See also
|
|
135
|
+
|
|
136
|
+
- docs/architecture.md §"Static header auth vs. real OAuth" — the other shape.
|
|
137
|
+
- `schema/servers.example.yaml` — the object form, with placeholders.
|
|
138
|
+
- trellis-mcp-oauth-static-client design.md — D1 (field shape), D2 (literal vs.
|
|
139
|
+
name), D3 (metadata wins over DCR), D4 (distribution boundary), D5 (no token
|
|
140
|
+
borrowing), D6 (this matrix's confidence notes).
|
package/docs/research.md
CHANGED
|
@@ -216,6 +216,17 @@ every agent's adapter renders it through the exact same reference mechanism
|
|
|
216
216
|
`env` already uses, and the pi bridge resolves it through the exact same
|
|
217
217
|
`resolveSecretEnv` call.
|
|
218
218
|
|
|
219
|
+
The same reference-not-value rule is what shapes OAuth client metadata
|
|
220
|
+
(trellis-mcp-oauth-static-client). A public client's `client_id` is published
|
|
221
|
+
by design — it rides in the browser URL on every authorization — so it is a
|
|
222
|
+
plain literal, comparable to how `mcp-remote --static-oauth-client-info` and
|
|
223
|
+
`claude mcp add --client-id` already treat it. A `client_secret` is the
|
|
224
|
+
opposite kind of thing, so it enters only as `client_secret_env`, a variable
|
|
225
|
+
NAME resolved through this same machinery; there is deliberately no literal
|
|
226
|
+
secret field. Which providers accept an unregistered client at all is a
|
|
227
|
+
per-provider question — see docs/mcp-oauth-matrix.md, including its note that
|
|
228
|
+
that matrix records observed behavior, not provider policy.
|
|
229
|
+
|
|
219
230
|
## pi coding agent — the one place we write real code, not config generation
|
|
220
231
|
|
|
221
232
|
Reverse-engineered directly from the installed binary
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-trellis",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "A unified Code Agent Runtime for Skills, MCP, Memory, and shared instructions across Claude Code, Codex, Kiro, pi, Kimi Code, and ZCode.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Paul Leo",
|
|
@@ -23,7 +23,9 @@
|
|
|
23
23
|
"files": [
|
|
24
24
|
"dist",
|
|
25
25
|
"schema",
|
|
26
|
-
"docs"
|
|
26
|
+
"docs/*.md",
|
|
27
|
+
"docs/assets/brand-v3",
|
|
28
|
+
"docs/assets/poster-series-v3"
|
|
27
29
|
],
|
|
28
30
|
"scripts": {
|
|
29
31
|
"build": "tsc -p tsconfig.json && node scripts/build-pi-bridge.mjs",
|
|
@@ -118,6 +118,24 @@ servers:
|
|
|
118
118
|
# Explicit OAuth classification keeps this server direct when an Agent
|
|
119
119
|
# uses gateway mode. Trellis never infers OAuth from a URL or 401.
|
|
120
120
|
# auth: oauth
|
|
121
|
+
#
|
|
122
|
+
# Object form (trellis-mcp-oauth-static-client): for a provider that
|
|
123
|
+
# rejects Dynamic Client Registration (Figma does — `unauthorized_client`)
|
|
124
|
+
# and requires a pre-registered client. `kind: oauth` is the only
|
|
125
|
+
# discriminator and the only required key; a bare `auth: oauth` above and
|
|
126
|
+
# a metadata-less `{ kind: oauth }` are exactly equivalent.
|
|
127
|
+
# - `client_id` is a PUBLIC literal by design — fine to commit. Use the
|
|
128
|
+
# identifier the PROVIDER published for this client; a self-registered
|
|
129
|
+
# one from your own account only if you accept managing it.
|
|
130
|
+
# - `client_secret_env` is a variable NAME, resolved through
|
|
131
|
+
# secrets.policy.yaml at `trellis mcp auth` time — never a secret
|
|
132
|
+
# value, and never a literal secret field (there is none).
|
|
133
|
+
# Placeholders below on purpose: only provider-published identifiers may
|
|
134
|
+
# ever be pre-filled in a distribution artifact.
|
|
135
|
+
# auth:
|
|
136
|
+
# kind: oauth
|
|
137
|
+
# client_id: "<provider-published-client-id>"
|
|
138
|
+
# client_secret_env: FIGMA_CLIENT_SECRET
|
|
121
139
|
|
|
122
140
|
# Example of a private/agent-specific server: only Claude Code has a use
|
|
123
141
|
# for this one, so the other three agents never see it defined at all.
|
package/docs/video/README.md
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
# Trellis 分享视频 · 素材与录制清单
|
|
2
|
-
|
|
3
|
-
> 本目录(`docs/video/`)在 `.gitignore` 中,所有内容只存在于本地,
|
|
4
|
-
> 不会进入开源仓库。
|
|
5
|
-
|
|
6
|
-
## 自动生成视频
|
|
7
|
-
|
|
8
|
-
```bash
|
|
9
|
-
node docs/video/generate-video.mjs # 输出 docs/video/trellis-demo-video.mp4
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
一条命令完成:重置沙盒 → 真实跑一遍 CLI 并捕获输出 → 渲染终端帧与卡片
|
|
13
|
-
(qlmanage)→ 系统 TTS 生成中文口播(Ting-Ting Enhanced)→ ffmpeg 合成
|
|
14
|
-
1920×1080 mp4。改口播文案直接编辑脚本里的 `blocks[].narration`;终端帧
|
|
15
|
-
内容来自真实命令输出,无需手改。依赖:ffmpeg(`brew install ffmpeg`)、
|
|
16
|
-
macOS 自带的 qlmanage/sips/say/afinfo。
|
|
17
|
-
|
|
18
|
-
## 演示沙盒(不碰真实配置)
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
bash scripts/video-demo-setup.sh # 生成/重置演示环境到 /tmp/trellis-demo-home
|
|
22
|
-
export HOME=/tmp/trellis-demo-home # 之后所有 trellis 命令都在沙盒里运行
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
沙盒内容:Claude Code(1 份指令 + 2 个 Skill + 2 个 MCP 服务器)、
|
|
26
|
-
Codex(config.toml + 1 个 MCP 服务器)。每次重录前重跑 setup 脚本即可
|
|
27
|
-
回到初始状态。已验证全流程可跑通:`init → onboard --dry-run → onboard →
|
|
28
|
-
doctor → rollback`。
|
|
29
|
-
|
|
30
|
-
录制用命令(已跳过交互选择,流程不打断):
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
trellis init
|
|
34
|
-
trellis onboard --dry-run --agent claude-code --manage codex
|
|
35
|
-
trellis onboard --agent claude-code --manage codex
|
|
36
|
-
trellis doctor
|
|
37
|
-
trellis rollback
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
## 终端与录屏设置
|
|
41
|
-
|
|
42
|
-
| 项 | 建议 |
|
|
43
|
-
|---|---|
|
|
44
|
-
| 终端主题 | 浅色(手机端观看对比度更好) |
|
|
45
|
-
| 字号 | 20–24pt,观众多用手机看 |
|
|
46
|
-
| 提示符 | `export PS1='$ '`,干净无干扰 |
|
|
47
|
-
| 窗口 | 1280×720 或 1440×810 逻辑分辨率 |
|
|
48
|
-
| 录屏 | Kap / QuickTime;每条 take 前 `clear` |
|
|
49
|
-
| 导出 | 横屏 1920×1080(B 站/YouTube);竖屏 1080×1920(视频号/小红书)则后期裁切,注意命令别超出安全区 |
|
|
50
|
-
|
|
51
|
-
## 分镜与素材对照
|
|
52
|
-
|
|
53
|
-
| 场景 | 画面 | 素材 |
|
|
54
|
-
|---|---|---|
|
|
55
|
-
| 1 开场 | 终端/编辑器随意状态 | 现场录 |
|
|
56
|
-
| 2 痛点 | `ls ~/.claude` `ls ~/.codex`(真实目录,只读) | 现场录 |
|
|
57
|
-
| 3 方案 | 海报全屏 | [`../assets/poster-series-v3/agent-trellis-poster-v3-unified-zh.png`](../assets/poster-series-v3/agent-trellis-poster-v3-unified-zh.png) |
|
|
58
|
-
| 4 演示 | 终端实录 | 沙盒命令(见上) |
|
|
59
|
-
| 5 设计点 | README Design principles 滚动 | github.com/paul-leo/Trellis |
|
|
60
|
-
| 6 收尾 | GitHub 仓库首页 + Star 按钮停留 2 秒 | 同上 |
|
|
61
|
-
|
|
62
|
-
## 其他可用素材
|
|
63
|
-
|
|
64
|
-
- 封面图/片尾卡:[`../assets/poster-series-v3/agent-trellis-poster-v3-horizontal-zh.png`](../assets/poster-series-v3/agent-trellis-poster-v3-horizontal-zh.png)
|
|
65
|
-
- Logo 叠层(角标):[`../assets/brand-v3/trellis-mark-v3-a.svg`](../assets/brand-v3/trellis-mark-v3-a.svg)
|
|
66
|
-
- 口播逐字稿:[voiceover.zh-CN.md](voiceover.zh-CN.md)
|
|
67
|
-
- 场景大纲:[outline.zh-CN.md](outline.zh-CN.md)
|
|
68
|
-
- 60 秒极简版:见 [outline.zh-CN.md](outline.zh-CN.md) 末尾
|
|
69
|
-
|
|
70
|
-
## 录制前 Checklist
|
|
71
|
-
|
|
72
|
-
- [ ] 重跑 `bash scripts/video-demo-setup.sh` 重置沙盒
|
|
73
|
-
- [ ] `export HOME=/tmp/trellis-demo-home && export PS1='$ ' && clear`
|
|
74
|
-
- [ ] 终端字号调大,关闭通知(勿扰模式)
|
|
75
|
-
- [ ] 预演一遍场景 4,确认输出与口播一致
|
|
76
|
-
- [ ] 麦克风电平测试 5 秒
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
file '/Users/pengzai/www/Trellis/docs/video/build/frames/05-interactive-5.png'
|
|
2
|
-
duration 1.952
|
|
3
|
-
file '/Users/pengzai/www/Trellis/docs/video/build/frames/05-interactive-6.png'
|
|
4
|
-
duration 4.556
|
|
5
|
-
file '/Users/pengzai/www/Trellis/docs/video/build/frames/05-interactive-6.png'
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|