agent-trellis 0.10.0 → 0.12.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.
Files changed (45) hide show
  1. package/dist/adapters/mcpPlan.d.ts +1 -0
  2. package/dist/adapters/mcpPlan.js +14 -5
  3. package/dist/cli.js +30 -5
  4. package/dist/commands/mcp.d.ts +71 -0
  5. package/dist/commands/mcp.js +145 -4
  6. package/dist/commands/mcpAuth.d.ts +6 -0
  7. package/dist/commands/mcpAuth.js +38 -10
  8. package/dist/commands/mcpGateway.js +7 -7
  9. package/dist/commands/skill.d.ts +45 -1
  10. package/dist/commands/skill.js +83 -2
  11. package/dist/core/canonical.d.ts +1 -0
  12. package/dist/core/canonical.js +8 -3
  13. package/dist/core/types.d.ts +4 -1
  14. package/dist/core/types.js +3 -0
  15. package/dist/lib/agentBridgeProvider.d.ts +1 -1
  16. package/dist/lib/gatewayBackend.d.ts +11 -0
  17. package/dist/lib/gatewayBackend.js +23 -4
  18. package/dist/lib/mcpConnect.d.ts +6 -3
  19. package/dist/lib/mcpConnect.js +8 -6
  20. package/dist/lib/mcpRuntime.d.ts +12 -2
  21. package/dist/lib/mcpRuntime.js +70 -9
  22. package/dist/lib/mcpStatusProvider.d.ts +1 -1
  23. package/dist/lib/memoryProvider.d.ts +1 -1
  24. package/dist/lib/oauth/discovery.d.ts +1 -0
  25. package/dist/lib/oauth/discovery.js +2 -0
  26. package/dist/lib/oauth/flow.d.ts +4 -0
  27. package/dist/lib/oauth/flow.js +48 -11
  28. package/dist/lib/oauth/refresh.d.ts +1 -0
  29. package/dist/lib/oauth/refresh.js +3 -1
  30. package/dist/lib/oauth/store.d.ts +2 -0
  31. package/dist/lib/runtimeControlProvider.d.ts +1 -1
  32. package/dist/lib/scopeSelection.d.ts +36 -0
  33. package/dist/lib/scopeSelection.js +65 -0
  34. package/dist/lib/skillManifest.d.ts +66 -0
  35. package/dist/lib/skillManifest.js +203 -0
  36. package/dist/lib/skillProvider.d.ts +21 -1
  37. package/dist/lib/skillProvider.js +61 -1
  38. package/dist/lib/taskProvider.d.ts +1 -1
  39. package/dist/lib/upstreamResources.d.ts +23 -0
  40. package/dist/lib/upstreamResources.js +192 -0
  41. package/dist/pi-bridge/bundle.js +37906 -19932
  42. package/docs/architecture.md +14 -13
  43. package/docs/mcp-authorization-ownership.md +59 -0
  44. package/docs/skills-over-mcp.md +91 -0
  45. package/package.json +6 -3
@@ -261,9 +261,9 @@ reach such a server at all.
261
261
 
262
262
  Gateway mode does not automatically take ownership of OAuth servers. Mark a
263
263
  server explicitly with `auth: oauth` (or `trellis mcp set <name> --auth oauth`)
264
- and gateway planning keeps it direct. This preserves the native Agent OAuth
265
- flow for Claude Code/Codex/Kiro; Pi's bridge is the client for its direct OAuth
266
- connection and may use Trellis's own OAuth store. Trellis never infers this
264
+ and gateway/runtime planning keeps it native. This preserves each Agent's own
265
+ OAuth identity. Only `auth: { kind: oauth, owner: trellis }` explicitly opts into
266
+ Trellis hosting, with a gateway/runtime route required. Trellis never infers this
267
267
  classification from a URL or a transient 401.
268
268
 
269
269
  The classification optionally carries pre-registered client metadata, for
@@ -288,18 +288,19 @@ be pre-filled.
288
288
  Trellis still implements the client half itself — discovery (RFC 8414 /
289
289
  RFC 9728), dynamic client registration (RFC 7591), authorization code with
290
290
  PKCE S256 (RFC 7636), and the refresh grant — in `src/lib/oauth/`, but that
291
- path is currently used for Pi/direct bridge connections rather than silently
292
- replacing native Agent authorization.
291
+ path is used for explicitly hosted connections. It never imports or silently
292
+ replaces native Agent authorization. See
293
+ [MCP authorization ownership](mcp-authorization-ownership.md).
293
294
 
294
295
  Two rules shape it, both from the constraint that the gateway is spawned
295
296
  silently by an agent with no terminal attached:
296
297
 
297
- - **Only an explicit human authorization command opens a browser.** Native
298
- clients use their own login command for direct OAuth entries. Pi's direct
299
- bridge uses `trellis mcp auth <server>`. The gateway never initiates an
300
- interactive flow and never connects an OAuth-marked server.
298
+ - **Only an explicit human action opens a browser.** Native clients use their
299
+ own authorization entry. Trellis-hosted connections can use the desktop
300
+ Authorize action or `trellis mcp auth <server>`. The gateway never initiates
301
+ an interactive flow and excludes Agent-owned OAuth servers.
301
302
  - **Refreshing is silent, and serialized by a lock.** A `refresh_token`
302
- grant needs neither a browser nor a callback, so the Pi direct bridge can
303
+ grant needs neither a browser nor a callback, so the hosted gateway can
303
304
  do it at connect time. The lock (`~/.trellis/mcp/oauth/<name>.lock`) exists
304
305
  because most authorization servers rotate the refresh token and
305
306
  invalidate its predecessor — two concurrent refreshes would leave one
@@ -312,8 +313,8 @@ non-interactive, no-GUI-session context the gateway runs in — measured,
312
313
  not assumed).
313
314
 
314
315
  In direct mode nothing here changes: each agent keeps using its own native
315
- OAuth flow. In gateway mode, an OAuth-marked server is also kept direct; only
316
- ordinary MCP servers enter the gateway.
316
+ OAuth flow. Gateway/runtime mode retains native entries for Agent-owned OAuth;
317
+ ordinary and explicitly Trellis-owned servers enter the gateway.
317
318
 
318
319
  ## MCP gateway mode
319
320
 
@@ -362,7 +363,7 @@ could reach disk.
362
363
  **What it changes for the agents:** Codex's single-`bearer_token_env_var`
363
364
  limitation stops applying, because Codex no longer receives any server's
364
365
  `headers` — the gateway holds them. OAuth-marked servers are intentionally
365
- kept direct; ordinary remote servers remain shared through the gateway. An
366
+ kept native by default; explicit Trellis ownership enables hosted OAuth. An
366
367
  upstream tool keeps its original name when that name is unique and longer than
367
368
  the short-name threshold; generic short names receive a compact
368
369
  `<server>__<tool>` prefix even when unique. A tool already carrying its source
@@ -0,0 +1,59 @@
1
+ # MCP authorization ownership
2
+
3
+ Each Agent-owned connection is authorized by that Agent. Trellis does not read,
4
+ copy or refresh its credentials. Existing `auth: oauth` and metadata-bearing
5
+ OAuth entries default to `owner: agent`. Runtime delivery also retains these
6
+ native OAuth entries beside the Trellis runtime.
7
+
8
+ The MCP desktop view labels native state as unknown and shows the relevant Agent
9
+ entry or guidance. A stray Trellis token does not change that state. The view's
10
+ credential badge describes stored credentials, not connection health.
11
+
12
+ ## Explicit Trellis hosting
13
+
14
+ For providers that accept a Trellis registration, opt in per server:
15
+
16
+ ```yaml
17
+ auth:
18
+ kind: oauth
19
+ owner: trellis
20
+ # Optional provider-published client identifier:
21
+ # client_id: YOUR_REGISTERED_CLIENT_ID
22
+ # client_secret_env: YOUR_CLIENT_SECRET_VARIABLE
23
+ ```
24
+
25
+ Or run `trellis mcp set NAME --auth oauth --auth-owner trellis`, then sync.
26
+ Gateway or runtime delivery must be enabled for the receiving Agent. Plain
27
+ direct routing reports a conflict rather than moving Trellis's identity into a
28
+ native connection. `--auth-owner agent` returns the server to native ownership.
29
+ The desktop owner selector previews a plan and requires Apply before changing
30
+ canonical configuration and syncing it.
31
+
32
+ Remote connections without an OAuth classification can choose an owner directly
33
+ in the desktop selector. Its No OAuth classification option clears that setting;
34
+ neither choice starts a grant automatically.
35
+
36
+ The hosted desktop Authorize button launches the existing PKCE flow in the
37
+ system browser. Progress is observable, cancellation closes the callback, and
38
+ timeouts/provider failures permit retry. Repeated clicks share one active job.
39
+ Tokens are saved in the existing per-server 0600 store, never sent to the UI.
40
+ A changed endpoint/auth configuration during the grant prevents persistence.
41
+ Authorization actions require a trusted desktop/development Origin.
42
+
43
+ New credentials retain their MCP resource and authorization-server issuer.
44
+ Authorization, exchange and refresh send the resource indicator; callback issuer
45
+ is checked when supplied or advertised as required. A changed resource cannot
46
+ receive its previous bound credential. The final save shares the refresh lock,
47
+ so a cancelled grant cannot overwrite a concurrent refresh.
48
+
49
+ The gateway can silently refresh its own hosted credentials; it never opens a
50
+ browser. Agents with native connections continue using their own flows.
51
+
52
+ ## Verification
53
+
54
+ Run core tests and typecheck, GUI sidecar tests/typecheck and GUI smoke tests.
55
+ `npm run test:oauth-browser --workspace @trellis/gui` additionally uses installed
56
+ Google Chrome headlessly with a local authorization-server fixture. It exercises
57
+ real browser CORS, PKCE callback, progress, cancellation, retry and owner
58
+ confirmation without contacting a real provider or using personal credentials.
59
+ Desktop packaging and installed-app acceptance happen after these checks.
@@ -0,0 +1,91 @@
1
+ # Skills over MCP — what Trellis serves, and what it does not claim
2
+
3
+ The MCP Skills extension (`io.modelcontextprotocol/skills`, SEP-2640, Final)
4
+ defines how a server publishes Agent Skills through the Resources primitive.
5
+ Trellis's runtime serves its canonical skills in that shape. This page records
6
+ the exact behavior, including what is deliberately *not* done.
7
+
8
+ ## What is served
9
+
10
+ For each canonical skill in the requesting agent's scope:
11
+
12
+ - `skill://<name>/SKILL.md` and every supporting file at
13
+ `skill://<name>/<relative-path>`, through `resources/list` and
14
+ `resources/read`.
15
+ - `skills/list` and `skills/get`, returning the specified entry: the skill's
16
+ `uri`, its frontmatter verbatim, and a complete manifest of
17
+ `{ uri, digest, size }` per file, with `resultType`, `ttlMs` and `cacheScope`.
18
+ `cacheScope` is `private` because the catalog differs per agent.
19
+
20
+ The existing surface is unchanged: `trellis.skills.search|read|read_file` and
21
+ `trellis://skills/<name>/SKILL.md` keep working exactly as before. The
22
+ `skill://` view is a second, additive view of the same data.
23
+
24
+ ## The manifest is computed from the bytes served
25
+
26
+ `digest` is `sha256:` plus 64 lowercase hex characters of the raw bytes;
27
+ `size` is their length. The manifest and `resources/read` use the same bounded
28
+ byte reader. Hosts still verify the retained manifest: a file can change between
29
+ listing and reading. Invalid UTF-8 is returned as
30
+ a base64 `blob` rather than lossy `text`, so the bytes a host verifies are the
31
+ bytes that were hashed.
32
+
33
+ A file the reader refuses — secret-shaped path, hidden file or directory,
34
+ `node_modules`, anything resolving outside the skill root, oversized — is absent
35
+ from the manifest and unreadable, both. A skill with more than 512 files or
36
+ 16 MiB is omitted whole and reported on stderr, never published with a partial
37
+ manifest.
38
+
39
+ A skill is served under `skill://` only when its directory name equals its
40
+ frontmatter `name`, that name is a valid Agent Skills name (lowercase letters,
41
+ digits, single hyphens), and it has a non-empty `description`. Otherwise it is
42
+ omitted and the reason is reported once. It stays reachable through the existing
43
+ tools.
44
+
45
+ ## A digest is consistency, not trust
46
+
47
+ The extension is explicit that digests are unsigned and that an intermediary can
48
+ rewrite entry and content together. A matching digest tells a host the bytes
49
+ match the manifest; it says nothing about whether the content is safe. Nothing in
50
+ Trellis treats a match as an authorization.
51
+
52
+ ## Discovery and protocol compatibility
53
+
54
+ The runtime uses the official TypeScript SDK v2 serving entry. Modern clients
55
+ discover resources and the `io.modelcontextprotocol/skills` extension through
56
+ `server/discover`; legacy clients can still initialize and call existing tools
57
+ and resources. Merely constructing a v2 Server is not sufficient: the runtime
58
+ explicitly uses `serveStdio` to select modern or legacy behavior.
59
+
60
+ Skills list/get are registered custom methods with parameter/result schemas.
61
+ The SDK handles modern request metadata, result discrimination and server
62
+ identity. Unknown methods still return JSON-RPC `-32601`. A legacy host can use
63
+ ordinary resources/tools even if it does not understand the Skills extension.
64
+
65
+ ## Upstream resources and skills
66
+
67
+ The gateway negotiates modern or legacy upstream behavior. Legacy HTTP+SSE uses
68
+ its existing transport. An upstream with resources but no tools remains valid.
69
+ Declared modern Skills catalogs are paginated, validated and relayed:
70
+
71
+ - URIs use a reversible `trellis-upstream://` namespace per source, preserving
72
+ final path segments and relative references. Provenance records the original
73
+ server label and URI. Canonical and equal-named upstream skills stay distinct.
74
+ - Listing does not fetch file content. Supporting files become readable from a
75
+ complete manifest, even when absent from `resources/list`; direct `skills/get`
76
+ also works for unlisted skills.
77
+ - Reads go back to the registered source and preserve exact bytes, digest and
78
+ size. Skill content is rejected if digest, size or SKILL.md frontmatter differ
79
+ from the entry. Refresh the entry before reading changed content.
80
+ - Dynamic skill manifests are currently declined with a diagnostic. Manifests
81
+ are bounded to 512 files and 16 MiB per skill; unsupported or malformed entries
82
+ do not remove other skills.
83
+ - No upstream skill is installed into `~/.trellis/skills`, activated, or given
84
+ execution permissions by the relay. The consuming host retains its own approval
85
+ and integrity checks.
86
+
87
+ Authorization ownership and the desktop flow are documented in
88
+ [MCP authorization ownership](mcp-authorization-ownership.md).
89
+
90
+ Protocol references: [SDK v2 migration](https://ts.sdk.modelcontextprotocol.io/v2/migration/support-2026-07-28)
91
+ and [Skills extension](https://modelcontextprotocol.io/extensions/skills/overview).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-trellis",
3
- "version": "0.10.0",
3
+ "version": "0.12.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",
@@ -34,7 +34,7 @@
34
34
  "pretest": "node scripts/build-pi-bridge.mjs",
35
35
  "test": "tsx --test \"test/unit/**/*.test.ts\"",
36
36
  "verify-pack": "node scripts/verify-pack.mjs",
37
- "prepublishOnly": "npm run typecheck && npm run build && npm test && npm run verify-pack"
37
+ "prepublishOnly": "npm run typecheck && npm run build && npm test"
38
38
  },
39
39
  "engines": {
40
40
  "node": ">=20"
@@ -61,7 +61,10 @@
61
61
  },
62
62
  "dependencies": {
63
63
  "@clack/prompts": "^1.8.1",
64
+ "@modelcontextprotocol/client": "^2.3.1",
64
65
  "@modelcontextprotocol/sdk": "^1.30.0",
65
- "yaml": "^2.9.1"
66
+ "@modelcontextprotocol/server": "^2.3.1",
67
+ "yaml": "^2.9.1",
68
+ "zod": "^4.6.5"
66
69
  }
67
70
  }