agent-trellis 0.7.0 → 0.8.2

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 (302) hide show
  1. package/README.md +48 -153
  2. package/dist/adapters/claude-code.js +3 -2
  3. package/dist/adapters/codex.js +3 -2
  4. package/dist/adapters/jsonMcp.d.ts +3 -1
  5. package/dist/adapters/jsonMcp.js +18 -4
  6. package/dist/adapters/kimi-code.d.ts +21 -0
  7. package/dist/adapters/kimi-code.js +107 -0
  8. package/dist/adapters/kiro.js +3 -2
  9. package/dist/adapters/mcpPlan.d.ts +6 -1
  10. package/dist/adapters/mcpPlan.js +106 -8
  11. package/dist/adapters/pi.js +22 -3
  12. package/dist/adapters/symlinkPlan.d.ts +7 -0
  13. package/dist/adapters/symlinkPlan.js +16 -7
  14. package/dist/adapters/zcode.d.ts +21 -0
  15. package/dist/adapters/zcode.js +234 -0
  16. package/dist/cli.js +145 -29
  17. package/dist/commands/doctor.d.ts +7 -2
  18. package/dist/commands/doctor.js +40 -2
  19. package/dist/commands/init.d.ts +4 -2
  20. package/dist/commands/init.js +29 -13
  21. package/dist/commands/kimi.d.ts +16 -0
  22. package/dist/commands/kimi.js +64 -0
  23. package/dist/commands/manage.d.ts +39 -0
  24. package/dist/commands/manage.js +126 -0
  25. package/dist/commands/mcp.d.ts +77 -14
  26. package/dist/commands/mcp.js +169 -29
  27. package/dist/commands/mcpGateway.d.ts +6 -0
  28. package/dist/commands/mcpGateway.js +35 -14
  29. package/dist/commands/mcpImport.d.ts +46 -0
  30. package/dist/commands/mcpImport.js +359 -0
  31. package/dist/commands/memory.d.ts +17 -3
  32. package/dist/commands/memory.js +27 -8
  33. package/dist/commands/migrate.d.ts +16 -5
  34. package/dist/commands/migrate.js +93 -17
  35. package/dist/commands/onboard.d.ts +74 -2
  36. package/dist/commands/onboard.js +469 -71
  37. package/dist/commands/rollback.js +28 -2
  38. package/dist/commands/secretsAudit.js +4 -1
  39. package/dist/commands/skill.d.ts +52 -6
  40. package/dist/commands/skill.js +114 -15
  41. package/dist/commands/sync.js +5 -1
  42. package/dist/core/adapter.d.ts +11 -1
  43. package/dist/core/canonical.d.ts +15 -7
  44. package/dist/core/canonical.js +101 -13
  45. package/dist/core/capabilitySelection.d.ts +45 -0
  46. package/dist/core/capabilitySelection.js +124 -0
  47. package/dist/core/types.d.ts +25 -2
  48. package/dist/core/types.js +8 -0
  49. package/dist/lib/agentBridge.d.ts +169 -0
  50. package/dist/lib/agentBridge.js +367 -0
  51. package/dist/lib/agentBridgeProvider.d.ts +14 -0
  52. package/dist/lib/agentBridgeProvider.js +95 -0
  53. package/dist/lib/backup.d.ts +32 -0
  54. package/dist/lib/backup.js +20 -1
  55. package/dist/lib/builtinSkills.d.ts +2 -0
  56. package/dist/lib/builtinSkills.js +4 -0
  57. package/dist/lib/chatAgents.d.ts +42 -0
  58. package/dist/lib/chatAgents.js +59 -0
  59. package/dist/lib/cliMetadata.d.ts +1 -0
  60. package/dist/lib/cliMetadata.js +14 -0
  61. package/dist/lib/envVarNames.d.ts +3 -0
  62. package/dist/lib/envVarNames.js +19 -0
  63. package/dist/lib/gatewayBackend.d.ts +28 -0
  64. package/dist/lib/gatewayBackend.js +72 -1
  65. package/dist/lib/installAgent.d.ts +7 -5
  66. package/dist/lib/installAgent.js +4 -3
  67. package/dist/lib/mcpConnect.js +5 -1
  68. package/dist/lib/mcpMigrateRead.d.ts +2 -0
  69. package/dist/lib/mcpMigrateRead.js +22 -1
  70. package/dist/lib/mcpRuntime.d.ts +46 -0
  71. package/dist/lib/mcpRuntime.js +185 -0
  72. package/dist/lib/mcpStatusProvider.d.ts +10 -0
  73. package/dist/lib/mcpStatusProvider.js +25 -0
  74. package/dist/lib/mcpToolRegistry.d.ts +18 -0
  75. package/dist/lib/mcpToolRegistry.js +107 -14
  76. package/dist/lib/memoryGraph.d.ts +1 -1
  77. package/dist/lib/memoryGraph.js +9 -3
  78. package/dist/lib/memoryProvider.d.ts +58 -0
  79. package/dist/lib/memoryProvider.js +175 -0
  80. package/dist/lib/memoryStatus.d.ts +17 -0
  81. package/dist/lib/memoryStatus.js +88 -0
  82. package/dist/lib/nativeMemory.d.ts +19 -0
  83. package/dist/lib/nativeMemory.js +129 -0
  84. package/dist/lib/realHomeSnapshot.js +5 -0
  85. package/dist/lib/runtimeControlProvider.d.ts +16 -0
  86. package/dist/lib/runtimeControlProvider.js +170 -0
  87. package/dist/lib/secretEnv.d.ts +2 -1
  88. package/dist/lib/secretEnv.js +6 -2
  89. package/dist/lib/skillProvider.d.ts +13 -0
  90. package/dist/lib/skillProvider.js +210 -0
  91. package/dist/lib/taskProvider.d.ts +7 -0
  92. package/dist/lib/taskProvider.js +43 -0
  93. package/dist/lib/taskStore.d.ts +46 -0
  94. package/dist/lib/taskStore.js +156 -0
  95. package/dist/lib/terminalPicker.d.ts +23 -49
  96. package/dist/lib/terminalPicker.js +80 -218
  97. package/dist/lib/zcodeOwnership.d.ts +17 -0
  98. package/dist/lib/zcodeOwnership.js +37 -0
  99. package/dist/pi-bridge/bundle.js +476 -37
  100. package/dist/pi-bridge/index.js +42 -21
  101. package/dist/pi-bridge/schemaTranslate.d.ts +4 -8
  102. package/dist/pi-bridge/schemaTranslate.js +4 -8
  103. package/dist/probes/codex.d.ts +7 -0
  104. package/dist/probes/codex.js +37 -5
  105. package/dist/probes/kimi-code.d.ts +12 -0
  106. package/dist/probes/kimi-code.js +55 -0
  107. package/dist/probes/zcode.d.ts +32 -0
  108. package/dist/probes/zcode.js +140 -0
  109. package/dist/sdk.d.ts +1 -1
  110. package/docs/architecture.md +230 -28
  111. package/docs/assets/brand-v3/trellis-mark-v3-a.png +0 -0
  112. package/docs/assets/brand-v3/trellis-mark-v3-a.svg +10 -0
  113. package/docs/assets/poster-series-v3/README.md +60 -0
  114. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-horizontal-en.png +0 -0
  115. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-horizontal-en.svg +51 -0
  116. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-horizontal-zh.png +0 -0
  117. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-horizontal-zh.svg +51 -0
  118. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-memory-en.png +0 -0
  119. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-memory-en.svg +48 -0
  120. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-memory-zh.png +0 -0
  121. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-memory-zh.svg +48 -0
  122. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-migrate-en.png +0 -0
  123. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-migrate-en.svg +56 -0
  124. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-migrate-zh.png +0 -0
  125. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-migrate-zh.svg +56 -0
  126. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-switch-en.png +0 -0
  127. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-switch-en.svg +47 -0
  128. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-switch-zh.png +0 -0
  129. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-switch-zh.svg +47 -0
  130. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-unified-en.png +0 -0
  131. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-unified-en.svg +51 -0
  132. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-unified-zh.png +0 -0
  133. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-unified-zh.svg +51 -0
  134. package/docs/getting-started.md +496 -42
  135. package/docs/overview.md +134 -0
  136. package/docs/overview.zh-CN.md +102 -0
  137. package/docs/research.md +59 -0
  138. package/docs/roadmap.md +11 -6
  139. package/docs/video/README.md +76 -0
  140. package/docs/video/build/audio/01-opening.aiff +0 -0
  141. package/docs/video/build/audio/01-opening.mp3 +0 -0
  142. package/docs/video/build/audio/02-pain.aiff +0 -0
  143. package/docs/video/build/audio/02-pain.mp3 +0 -0
  144. package/docs/video/build/audio/03-solution.aiff +0 -0
  145. package/docs/video/build/audio/03-solution.mp3 +0 -0
  146. package/docs/video/build/audio/04-install.aiff +0 -0
  147. package/docs/video/build/audio/04-install.mp3 +0 -0
  148. package/docs/video/build/audio/04-setup.mp3 +0 -0
  149. package/docs/video/build/audio/05-dryrun.mp3 +0 -0
  150. package/docs/video/build/audio/05-init.aiff +0 -0
  151. package/docs/video/build/audio/05-init.mp3 +0 -0
  152. package/docs/video/build/audio/05-interactive.mp3 +0 -0
  153. package/docs/video/build/audio/06-dryrun.aiff +0 -0
  154. package/docs/video/build/audio/06-dryrun.mp3 +0 -0
  155. package/docs/video/build/audio/06-onboard.mp3 +0 -0
  156. package/docs/video/build/audio/06-run.mp3 +0 -0
  157. package/docs/video/build/audio/07-onboard.aiff +0 -0
  158. package/docs/video/build/audio/07-onboard.mp3 +0 -0
  159. package/docs/video/build/audio/07-verify.mp3 +0 -0
  160. package/docs/video/build/audio/08-closing.mp3 +0 -0
  161. package/docs/video/build/audio/08-doctor.aiff +0 -0
  162. package/docs/video/build/audio/08-doctor.mp3 +0 -0
  163. package/docs/video/build/audio/09-rollback.aiff +0 -0
  164. package/docs/video/build/audio/09-rollback.mp3 +0 -0
  165. package/docs/video/build/audio/10-principles.aiff +0 -0
  166. package/docs/video/build/audio/10-principles.mp3 +0 -0
  167. package/docs/video/build/audio/11-closing.aiff +0 -0
  168. package/docs/video/build/audio/11-closing.mp3 +0 -0
  169. package/docs/video/build/frames/01-opening-0.png +0 -0
  170. package/docs/video/build/frames/02-pain-1.png +0 -0
  171. package/docs/video/build/frames/02-pain-2.png +0 -0
  172. package/docs/video/build/frames/03-solution-3.png +0 -0
  173. package/docs/video/build/frames/04-install-4.png +0 -0
  174. package/docs/video/build/frames/04-setup-4.png +0 -0
  175. package/docs/video/build/frames/04-setup-5.png +0 -0
  176. package/docs/video/build/frames/05-dryrun-6.png +0 -0
  177. package/docs/video/build/frames/05-init-5.png +0 -0
  178. package/docs/video/build/frames/05-interactive-5.png +0 -0
  179. package/docs/video/build/frames/05-interactive-6.png +0 -0
  180. package/docs/video/build/frames/06-dryrun-6.png +0 -0
  181. package/docs/video/build/frames/06-dryrun-7.png +0 -0
  182. package/docs/video/build/frames/06-onboard-7.png +0 -0
  183. package/docs/video/build/frames/06-onboard-8.png +0 -0
  184. package/docs/video/build/frames/06-run-7.png +0 -0
  185. package/docs/video/build/frames/06-run-8.png +0 -0
  186. package/docs/video/build/frames/07-onboard-10.png +0 -0
  187. package/docs/video/build/frames/07-onboard-7.png +0 -0
  188. package/docs/video/build/frames/07-onboard-8.png +0 -0
  189. package/docs/video/build/frames/07-onboard-9.png +0 -0
  190. package/docs/video/build/frames/07-verify-10.png +0 -0
  191. package/docs/video/build/frames/07-verify-8.png +0 -0
  192. package/docs/video/build/frames/07-verify-9.png +0 -0
  193. package/docs/video/build/frames/08-closing-10.png +0 -0
  194. package/docs/video/build/frames/08-closing-11.png +0 -0
  195. package/docs/video/build/frames/08-doctor-11.png +0 -0
  196. package/docs/video/build/frames/08-doctor-9.png +0 -0
  197. package/docs/video/build/frames/09-rollback-10.png +0 -0
  198. package/docs/video/build/frames/09-rollback-12.png +0 -0
  199. package/docs/video/build/frames/10-principles-11.png +0 -0
  200. package/docs/video/build/frames/10-principles-13.png +0 -0
  201. package/docs/video/build/frames/11-closing-12.png +0 -0
  202. package/docs/video/build/frames/11-closing-14.png +0 -0
  203. package/docs/video/build/segments/01-opening.mp4 +0 -0
  204. package/docs/video/build/segments/01-opening.txt +3 -0
  205. package/docs/video/build/segments/02-pain.mp4 +0 -0
  206. package/docs/video/build/segments/02-pain.txt +5 -0
  207. package/docs/video/build/segments/03-solution.mp4 +0 -0
  208. package/docs/video/build/segments/03-solution.txt +3 -0
  209. package/docs/video/build/segments/04-install.mp4 +0 -0
  210. package/docs/video/build/segments/04-install.txt +3 -0
  211. package/docs/video/build/segments/04-setup.mp4 +0 -0
  212. package/docs/video/build/segments/04-setup.txt +3 -0
  213. package/docs/video/build/segments/05-dryrun.mp4 +0 -0
  214. package/docs/video/build/segments/05-dryrun.txt +3 -0
  215. package/docs/video/build/segments/05-init.mp4 +0 -0
  216. package/docs/video/build/segments/05-init.txt +3 -0
  217. package/docs/video/build/segments/05-interactive.mp4 +0 -0
  218. package/docs/video/build/segments/05-interactive.txt +5 -0
  219. package/docs/video/build/segments/06-dryrun.mp4 +0 -0
  220. package/docs/video/build/segments/06-dryrun.txt +3 -0
  221. package/docs/video/build/segments/06-onboard.mp4 +0 -0
  222. package/docs/video/build/segments/06-onboard.txt +5 -0
  223. package/docs/video/build/segments/06-run.mp4 +0 -0
  224. package/docs/video/build/segments/06-run.txt +3 -0
  225. package/docs/video/build/segments/07-onboard.mp4 +0 -0
  226. package/docs/video/build/segments/07-onboard.txt +5 -0
  227. package/docs/video/build/segments/07-verify.mp4 +0 -0
  228. package/docs/video/build/segments/07-verify.txt +5 -0
  229. package/docs/video/build/segments/08-closing.mp4 +0 -0
  230. package/docs/video/build/segments/08-closing.txt +3 -0
  231. package/docs/video/build/segments/08-doctor.mp4 +0 -0
  232. package/docs/video/build/segments/08-doctor.txt +3 -0
  233. package/docs/video/build/segments/09-rollback.mp4 +0 -0
  234. package/docs/video/build/segments/09-rollback.txt +3 -0
  235. package/docs/video/build/segments/10-principles.mp4 +0 -0
  236. package/docs/video/build/segments/10-principles.txt +3 -0
  237. package/docs/video/build/segments/11-closing.mp4 +0 -0
  238. package/docs/video/build/segments/11-closing.txt +3 -0
  239. package/docs/video/build/segments/final.txt +8 -0
  240. package/docs/video/build-ai/audio/01-hook.mp3 +0 -0
  241. package/docs/video/build-ai/audio/02-pain.mp3 +0 -0
  242. package/docs/video/build-ai/audio/03-solution.mp3 +0 -0
  243. package/docs/video/build-ai/audio/04-how.mp3 +0 -0
  244. package/docs/video/build-ai/audio/05-safe.mp3 +0 -0
  245. package/docs/video/build-ai/audio/06-closing.mp3 +0 -0
  246. package/docs/video/build-ai/clips/01-hook.mp4 +0 -0
  247. package/docs/video/build-ai/clips/02-pain.mp4 +0 -0
  248. package/docs/video/build-ai/clips/03-solution.mp4 +0 -0
  249. package/docs/video/build-ai/clips/04-how.mp4 +0 -0
  250. package/docs/video/build-ai/clips/05-safe.mp4 +0 -0
  251. package/docs/video/build-ai/clips/06-closing.mp4 +0 -0
  252. package/docs/video/build-ai/first-frame-02-pain.png +0 -0
  253. package/docs/video/build-ai/first-frame-03-solution.png +0 -0
  254. package/docs/video/build-ai/first-frame-04-how.png +0 -0
  255. package/docs/video/build-ai/first-frame-05-safe.png +0 -0
  256. package/docs/video/build-ai/segments/01-hook.caption.txt +2 -0
  257. package/docs/video/build-ai/segments/01-hook.mp4 +0 -0
  258. package/docs/video/build-ai/segments/02-pain.mp4 +0 -0
  259. package/docs/video/build-ai/segments/03-solution.mp4 +0 -0
  260. package/docs/video/build-ai/segments/04-how.mp4 +0 -0
  261. package/docs/video/build-ai/segments/05-safe.mp4 +0 -0
  262. package/docs/video/build-ai/segments/06-closing.mp4 +0 -0
  263. package/docs/video/build-ai/segments/cap-01-hook.png +0 -0
  264. package/docs/video/build-ai/segments/cap-02-pain.png +0 -0
  265. package/docs/video/build-ai/segments/cap-03-solution.png +0 -0
  266. package/docs/video/build-ai/segments/cap-04-how.png +0 -0
  267. package/docs/video/build-ai/segments/cap-05-safe.png +0 -0
  268. package/docs/video/build-ai/segments/cap-06-closing.png +0 -0
  269. package/docs/video/build-ai/segments/final.txt +6 -0
  270. package/docs/video/build-posters/audio/01-hook.mp3 +0 -0
  271. package/docs/video/build-posters/audio/02-pain.mp3 +0 -0
  272. package/docs/video/build-posters/audio/03-solution.mp3 +0 -0
  273. package/docs/video/build-posters/audio/04-how.mp3 +0 -0
  274. package/docs/video/build-posters/audio/05-safe.mp3 +0 -0
  275. package/docs/video/build-posters/audio/06-closing.mp3 +0 -0
  276. package/docs/video/build-posters/cap-01-hook.png +0 -0
  277. package/docs/video/build-posters/cap-02-pain.png +0 -0
  278. package/docs/video/build-posters/cap-03-solution.png +0 -0
  279. package/docs/video/build-posters/cap-04-how.png +0 -0
  280. package/docs/video/build-posters/cap-05-safe.png +0 -0
  281. package/docs/video/build-posters/cap-06-closing.png +0 -0
  282. package/docs/video/build-posters/card-01-hook.png +0 -0
  283. package/docs/video/build-posters/card-06-closing.png +0 -0
  284. package/docs/video/build-posters/segments/01-hook.mp4 +0 -0
  285. package/docs/video/build-posters/segments/02-pain.mp4 +0 -0
  286. package/docs/video/build-posters/segments/03-solution.mp4 +0 -0
  287. package/docs/video/build-posters/segments/04-how.mp4 +0 -0
  288. package/docs/video/build-posters/segments/05-safe.mp4 +0 -0
  289. package/docs/video/build-posters/segments/06-closing.mp4 +0 -0
  290. package/docs/video/build-posters/segments/final.txt +6 -0
  291. package/docs/video/generate-video-ai.mjs +334 -0
  292. package/docs/video/generate-video-posters.mjs +204 -0
  293. package/docs/video/generate-video.mjs +426 -0
  294. package/docs/video/outline.zh-CN.md +102 -0
  295. package/docs/video/trellis-demo-video-ai.mp4 +0 -0
  296. package/docs/video/trellis-demo-video.mp4 +0 -0
  297. package/docs/video/voiceover.zh-CN.md +49 -0
  298. package/package.json +6 -2
  299. package/schema/builtin-skills/trellis-runtime/SKILL.md +117 -0
  300. package/schema/capability-selection.example.yaml +23 -0
  301. package/schema/scope.example.yaml +1 -1
  302. package/schema/servers.example.yaml +15 -1
@@ -15,29 +15,17 @@ import { homedir } from "node:os";
15
15
  import { loadCanonicalSource } from "../core/canonical.js";
16
16
  import { resolveMcpPlan } from "../adapters/mcpPlan.js";
17
17
  import { connectServer, withTimeout, DEFAULT_CONNECT_TIMEOUT_MS } from "../lib/mcpConnect.js";
18
+ import { McpToolRegistry } from "../lib/mcpToolRegistry.js";
19
+ import { withOAuthHeader } from "../lib/gatewayBackend.js";
18
20
  import { ALL_AGENTS } from "../core/types.js";
19
- import { bridgedToolName, toParametersSchema, toPiContent } from "./schemaTranslate.js";
21
+ import { toParametersSchema, toPiContent } from "./schemaTranslate.js";
20
22
  /** Re-exported so `trellis-mcp-connect-timeout`'s existing test keeps
21
23
  * importing it from the module it was written against — proving the
22
24
  * extraction changed nothing it could observe. */
23
25
  export { withTimeout };
24
26
  const CLIENT_INFO = { name: "trellis-mcp-bridge", version: "0.0.0" };
25
- function registerServerTools(pi, serverName, client, timeoutMs) {
26
- return withTimeout(client.listTools(), timeoutMs, `listTools timed out after ${timeoutMs}ms`).then((result) => {
27
- for (const tool of result.tools) {
28
- pi.registerTool({
29
- name: bridgedToolName(serverName, tool.name),
30
- label: tool.name,
31
- description: tool.description ?? `MCP tool "${tool.name}" from server "${serverName}"`,
32
- parameters: toParametersSchema(tool.inputSchema),
33
- async execute(_toolCallId, params) {
34
- const result = await client.callTool({ name: tool.name, arguments: params });
35
- const content = Array.isArray(result.content) ? result.content : [];
36
- return { content: toPiContent(content), details: result };
37
- },
38
- });
39
- }
40
- });
27
+ function listServerTools(client, timeoutMs) {
28
+ return withTimeout(client.listTools(), timeoutMs, `listTools timed out after ${timeoutMs}ms`).then((result) => result.tools);
41
29
  }
42
30
  /**
43
31
  * `homeDir`/`connectTimeoutMs` default to the real `~` / 10s — only
@@ -57,6 +45,7 @@ export default async function trellisMcpBridge(pi, homeDir = homedir(), connectT
57
45
  // is pi reading canonical directly at its own runtime, P4's own concern.
58
46
  const { desired } = resolveMcpPlan("pi", canonical.mcp, ALL_AGENTS, canonical.secretsPolicy);
59
47
  const clients = new Set();
48
+ const registry = new McpToolRegistry();
60
49
  const closeClient = async (client) => {
61
50
  if (!clients.delete(client))
62
51
  return;
@@ -83,25 +72,57 @@ export default async function trellisMcpBridge(pi, homeDir = homedir(), connectT
83
72
  // pi 0.85.x emits this before tearing down an extension runtime. Keep the
84
73
  // hook optional so the bridge remains loadable in older compatible hosts.
85
74
  pi.on?.("session_shutdown", closeAllClients);
86
- await Promise.all(desired.map(async ({ name, def }) => {
75
+ const discovered = await Promise.all(desired.map(async ({ name, def }) => {
87
76
  let client;
88
77
  try {
89
- client = await connectServer(def, canonical.secretsPolicy, connectTimeoutMs, CLIENT_INFO);
78
+ const effectiveDef = def.auth === "oauth" && def.url
79
+ ? await withOAuthHeader(name, def, homeDir)
80
+ : def;
81
+ client = await connectServer(effectiveDef, canonical.secretsPolicy, connectTimeoutMs, CLIENT_INFO);
90
82
  }
91
83
  catch (err) {
92
84
  // One unreachable/misconfigured (including permanently hanging —
93
85
  // trellis-mcp-connect-timeout) server must never prevent every
94
86
  // other server's tools from registering (tasks.md 3.2).
95
87
  console.error(`trellis-mcp-bridge: failed to connect to MCP server "${name}": ${err instanceof Error ? err.message : String(err)}`);
96
- return;
88
+ return undefined;
97
89
  }
98
90
  clients.add(client);
99
91
  try {
100
- await registerServerTools(pi, name, client, connectTimeoutMs);
92
+ const tools = await listServerTools(client, connectTimeoutMs);
93
+ return { name, client, tools };
101
94
  }
102
95
  catch (err) {
103
96
  console.error(`trellis-mcp-bridge: failed to list tools for MCP server "${name}": ${err instanceof Error ? err.message : String(err)}`);
104
97
  await closeClient(client);
98
+ return undefined;
105
99
  }
106
100
  }));
101
+ // Add in canonical plan order, not completion order, so allocation remains
102
+ // stable when multiple upstreams answer concurrently.
103
+ for (const result of discovered) {
104
+ if (!result)
105
+ continue;
106
+ registry.add(result.name, result.client, result.tools);
107
+ }
108
+ for (const tool of registry.listTools()) {
109
+ const target = registry.resolve(tool.name);
110
+ if (!target)
111
+ continue;
112
+ const originalName = target.toolName;
113
+ const serverName = target.serverName;
114
+ pi.registerTool({
115
+ name: tool.name,
116
+ label: originalName,
117
+ description: tool.description ?? `MCP tool "${originalName}" from server "${serverName}"`,
118
+ parameters: toParametersSchema(tool.inputSchema),
119
+ async execute(_toolCallId, params) {
120
+ const result = await registry.callTool(tool.name, params);
121
+ const content = Array.isArray(result.content)
122
+ ? result.content
123
+ : [];
124
+ return { content: toPiContent(content), details: result };
125
+ },
126
+ });
127
+ }
107
128
  }
@@ -50,12 +50,8 @@ export declare function toParametersSchema(inputSchema: unknown): TSchema;
50
50
  * own `AgentToolResult.content` has no representation for them
51
51
  * (design.md D3). */
52
52
  export declare function toPiContent(items: McpContentItem[]): PiContent[];
53
- /** `${serverName}__${toolName}` — deterministic, collision-free across
54
- * servers sharing pi.registerTool()'s single flat namespace (design.md D5).
55
- *
56
- * Now one implementation shared with the gateway's own aggregation rather
57
- * than two identical ones: the naming convention is the contract between
58
- * a prefixed name and the server it routes to, and two copies of it could
59
- * drift into routing tools to the wrong upstream
60
- * (trellis-mcp-gateway-hosting design.md D3). */
53
+ /** Legacy direct prefix helper kept for callers/tests that need to render a
54
+ * source-qualified name. The live bridge uses `McpToolRegistry` so it can
55
+ * allocate short names across all connected servers, normalize invalid
56
+ * characters, and retain the raw name for routing. */
61
57
  export { prefixedToolName as bridgedToolName } from "../lib/mcpToolRegistry.js";
@@ -33,12 +33,8 @@ export function toPiContent(items) {
33
33
  }
34
34
  });
35
35
  }
36
- /** `${serverName}__${toolName}` — deterministic, collision-free across
37
- * servers sharing pi.registerTool()'s single flat namespace (design.md D5).
38
- *
39
- * Now one implementation shared with the gateway's own aggregation rather
40
- * than two identical ones: the naming convention is the contract between
41
- * a prefixed name and the server it routes to, and two copies of it could
42
- * drift into routing tools to the wrong upstream
43
- * (trellis-mcp-gateway-hosting design.md D3). */
36
+ /** Legacy direct prefix helper kept for callers/tests that need to render a
37
+ * source-qualified name. The live bridge uses `McpToolRegistry` so it can
38
+ * allocate short names across all connected servers, normalize invalid
39
+ * characters, and retain the raw name for routing. */
44
40
  export { prefixedToolName as bridgedToolName } from "../lib/mcpToolRegistry.js";
@@ -21,4 +21,11 @@ export interface ProbeOptions {
21
21
  * default — see docs/architecture.md "MCP handshake probing is opt-in". */
22
22
  probeMcp?: boolean;
23
23
  }
24
+ /**
25
+ * Codex resolves its config through HOME, but Volta's shim resolves its own
26
+ * installation through VOLTA_HOME. A probe against a scratch HOME must keep
27
+ * those identities separate or `codex mcp list` fails before it can read the
28
+ * scratch config.
29
+ */
30
+ export declare function codexEnv(homeDir: string, env?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
24
31
  export declare function probe(homeDir?: string, opts?: ProbeOptions): Promise<AgentSnapshot>;
@@ -11,7 +11,7 @@
11
11
  import { execFileSync } from "node:child_process";
12
12
  import { existsSync, readFileSync } from "node:fs";
13
13
  import { homedir } from "node:os";
14
- import { join } from "node:path";
14
+ import { delimiter, join } from "node:path";
15
15
  import { probeMcpServer } from "../lib/mcpProbe.js";
16
16
  import { pathRef, resolveEnvRefs, scanSkillRoot } from "../lib/probeCommon.js";
17
17
  /**
@@ -30,6 +30,30 @@ export function readInstructionsPath(configTomlPath) {
30
30
  }
31
31
  return /^\s*instructions\s*=\s*"([^"]*)"/m.exec(content)?.[1];
32
32
  }
33
+ /**
34
+ * Codex resolves its config through HOME, but Volta's shim resolves its own
35
+ * installation through VOLTA_HOME. A probe against a scratch HOME must keep
36
+ * those identities separate or `codex mcp list` fails before it can read the
37
+ * scratch config.
38
+ */
39
+ export function codexEnv(homeDir, env = process.env) {
40
+ const voltaHome = env.VOLTA_HOME ?? join(homedir(), ".volta");
41
+ const voltaBin = join(voltaHome, "bin");
42
+ const pathParts = (env.PATH ?? "").split(delimiter).filter(Boolean);
43
+ const hasVolta = existsSync(voltaBin);
44
+ if (hasVolta && !pathParts.includes(voltaBin))
45
+ pathParts.unshift(voltaBin);
46
+ return {
47
+ ...env,
48
+ HOME: homeDir,
49
+ // A host may inject CODEX_HOME for its own relay/session state. It has
50
+ // higher priority than HOME inside Codex, so override it as well or a
51
+ // scratch-home probe silently reads the host's real configuration.
52
+ CODEX_HOME: join(homeDir, ".codex"),
53
+ ...(hasVolta ? { VOLTA_HOME: voltaHome } : {}),
54
+ ...(pathParts.length ? { PATH: pathParts.join(delimiter) } : {}),
55
+ };
56
+ }
33
57
  export async function probe(homeDir = homedir(), opts = {}) {
34
58
  const configTomlPath = join(homeDir, ".codex", "config.toml");
35
59
  if (!existsSync(configTomlPath)) {
@@ -43,21 +67,29 @@ export async function probe(homeDir = homedir(), opts = {}) {
43
67
  // default `homeDir` would silently get this real machine's real MCP
44
68
  // server list instead (trellis-migrate-mcp-servers found this gap in
45
69
  // src/lib/mcpMigrateRead.ts's own equivalent call; fixed there first).
46
- const codexEnv = { ...process.env, HOME: homeDir };
70
+ const scopedCodexEnv = codexEnv(homeDir);
47
71
  let version;
48
72
  try {
49
- version = execFileSync("codex", ["--version"], { encoding: "utf-8", timeout: 5_000, env: codexEnv }).trim();
73
+ version = execFileSync("codex", ["--version"], { encoding: "utf-8", timeout: 5_000, env: scopedCodexEnv }).trim();
50
74
  }
51
75
  catch {
52
76
  // config exists without the binary on PATH — unusual, still probeable
53
77
  }
54
78
  let mcpEntries = [];
55
79
  try {
56
- const raw = execFileSync("codex", ["mcp", "list", "--json"], { encoding: "utf-8", timeout: 5_000, env: codexEnv });
80
+ const raw = execFileSync("codex", ["mcp", "list", "--json"], { encoding: "utf-8", timeout: 5_000, env: scopedCodexEnv });
57
81
  mcpEntries = JSON.parse(raw);
58
82
  }
59
83
  catch (err) {
60
- diagnostics.push(`codex mcp list --json failed: ${err instanceof Error ? err.message : String(err)}`);
84
+ // ENOENT means the binary itself isn't on PATH — the same benign,
85
+ // config-without-binary condition the `--version` check above already
86
+ // swallows silently, not a real failure worth alarming the user with a
87
+ // raw spawn error string. Anything else (malformed JSON, a non-zero
88
+ // exit for another reason, a timeout) is a genuine, unexpected failure
89
+ // and stays a diagnostic.
90
+ if (err?.code !== "ENOENT") {
91
+ diagnostics.push(`codex mcp list --json failed: ${err instanceof Error ? err.message : String(err)}`);
92
+ }
61
93
  }
62
94
  const mcpServers = mcpEntries.map((entry) => ({
63
95
  name: entry.name,
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Kimi Code probe. Kimi 2.x stores user MCP declarations in
3
+ * `~/.kimi-code/mcp.json`, user Skills in `~/.kimi-code/skills`, and global
4
+ * instructions in `~/.kimi-code/AGENTS.md`. Kimi also discovers the generic
5
+ * `~/.agents/skills` root; it is reported so doctor can observe it, while the
6
+ * Runtime-only launcher can explicitly isolate it later.
7
+ */
8
+ import type { AgentSnapshot } from "../core/types.js";
9
+ export interface ProbeOptions {
10
+ probeMcp?: boolean;
11
+ }
12
+ export declare function probe(homeDir?: string, opts?: ProbeOptions): Promise<AgentSnapshot>;
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Kimi Code probe. Kimi 2.x stores user MCP declarations in
3
+ * `~/.kimi-code/mcp.json`, user Skills in `~/.kimi-code/skills`, and global
4
+ * instructions in `~/.kimi-code/AGENTS.md`. Kimi also discovers the generic
5
+ * `~/.agents/skills` root; it is reported so doctor can observe it, while the
6
+ * Runtime-only launcher can explicitly isolate it later.
7
+ */
8
+ import { execFileSync } from "node:child_process";
9
+ import { homedir } from "node:os";
10
+ import { join } from "node:path";
11
+ import { probeMcpServer } from "../lib/mcpProbe.js";
12
+ import { pathRef, readJsonFile, resolveEnvRefs, scanSkillRoot } from "../lib/probeCommon.js";
13
+ function kimiEnv(homeDir) {
14
+ return { ...process.env, HOME: homeDir, KIMI_CODE_HOME: join(homeDir, ".kimi-code") };
15
+ }
16
+ export async function probe(homeDir = homedir(), opts = {}) {
17
+ const root = join(homeDir, ".kimi-code");
18
+ const mcpPath = join(root, "mcp.json");
19
+ const mcpConfig = readJsonFile(mcpPath);
20
+ const kimiRoot = pathRef(root);
21
+ if (kimiRoot === undefined) {
22
+ return { agent: "kimi-code", present: false, skillRoots: [], mcpServers: [], diagnostics: [] };
23
+ }
24
+ let version;
25
+ try {
26
+ version = execFileSync("kimi", ["--version"], { encoding: "utf-8", timeout: 5_000, env: kimiEnv(homeDir) }).trim();
27
+ }
28
+ catch {
29
+ // A config-only fixture remains probeable without a binary on PATH.
30
+ }
31
+ const mcpServers = Object.entries(mcpConfig?.mcpServers ?? {}).map(([name, def]) => ({
32
+ name,
33
+ transport: def.url ? (def.transport === "sse" ? "sse" : "http") : "stdio",
34
+ }));
35
+ if (opts.probeMcp) {
36
+ await Promise.all(Object.entries(mcpConfig?.mcpServers ?? {}).map(async ([name, def], index) => {
37
+ if (def.url || !def.command)
38
+ return;
39
+ mcpServers[index].probe = await probeMcpServer({ transport: "stdio", command: def.command, args: def.args }, resolveEnvRefs(def.env, kimiEnv(homeDir)));
40
+ }));
41
+ }
42
+ const skillRoots = [
43
+ scanSkillRoot(join(root, "skills")),
44
+ scanSkillRoot(join(homeDir, ".agents", "skills")),
45
+ ].filter((entry) => entry !== undefined);
46
+ return {
47
+ agent: "kimi-code",
48
+ present: true,
49
+ version,
50
+ skillRoots,
51
+ mcpServers,
52
+ instructionsFile: pathRef(join(root, "AGENTS.md")),
53
+ diagnostics: [],
54
+ };
55
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * ZCode probe and profile selection.
3
+ *
4
+ * ZCode has two public configuration layouts in circulation. The official
5
+ * source/distribution reads ~/.zcode/cli/config.json, while the installed
6
+ * zcode-app-cli compatibility distribution keeps runtime settings (including
7
+ * mcp.servers) in ~/.zcode/cli/setting.json. We select one profile before any
8
+ * adapter plans a write; writing both would make ZCode's native precedence
9
+ * ambiguous and can hide a managed MCP entry.
10
+ */
11
+ import type { AgentSnapshot } from "../core/types.js";
12
+ export type ZcodeProfileKind = "community-cli" | "official" | "configuration-only";
13
+ export interface ZcodeProfile {
14
+ kind: ZcodeProfileKind;
15
+ configPath: string;
16
+ executable?: string;
17
+ executableVersion?: string;
18
+ supportsExecution: boolean;
19
+ }
20
+ export interface ProbeOptions {
21
+ probeMcp?: boolean;
22
+ env?: NodeJS.ProcessEnv;
23
+ }
24
+ export declare function zcodeEnv(homeDir: string, env?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
25
+ export declare function selectZcodeProfile(homeDir: string, facts?: {
26
+ command?: string;
27
+ version?: string;
28
+ help?: string;
29
+ outputFormatSupported?: boolean;
30
+ }): ZcodeProfile | undefined;
31
+ export declare function resolveZcodeProfile(homeDir?: string, env?: NodeJS.ProcessEnv): ZcodeProfile | undefined;
32
+ export declare function probe(homeDir?: string, opts?: ProbeOptions): Promise<AgentSnapshot>;
@@ -0,0 +1,140 @@
1
+ /**
2
+ * ZCode probe and profile selection.
3
+ *
4
+ * ZCode has two public configuration layouts in circulation. The official
5
+ * source/distribution reads ~/.zcode/cli/config.json, while the installed
6
+ * zcode-app-cli compatibility distribution keeps runtime settings (including
7
+ * mcp.servers) in ~/.zcode/cli/setting.json. We select one profile before any
8
+ * adapter plans a write; writing both would make ZCode's native precedence
9
+ * ambiguous and can hide a managed MCP entry.
10
+ */
11
+ import { execFileSync } from "node:child_process";
12
+ import { existsSync } from "node:fs";
13
+ import { homedir } from "node:os";
14
+ import { delimiter, join } from "node:path";
15
+ import { probeMcpServer } from "../lib/mcpProbe.js";
16
+ import { pathRef, readJsonFile, resolveEnvRefs, scanSkillRoot } from "../lib/probeCommon.js";
17
+ export function zcodeEnv(homeDir, env = process.env) {
18
+ // A Node host can inherit Volta's selected Node binary without inheriting
19
+ // Volta's shim directory in PATH. Keep the user's explicit PATH order, but
20
+ // add the documented Volta bin location when necessary so `zcode` resolves
21
+ // the same way it does in their interactive terminal.
22
+ const voltaBin = env.VOLTA_HOME ? join(env.VOLTA_HOME, "bin") : undefined;
23
+ const pathParts = (env.PATH ?? "").split(delimiter).filter(Boolean);
24
+ if (voltaBin && !pathParts.includes(voltaBin))
25
+ pathParts.unshift(voltaBin);
26
+ return { ...env, HOME: homeDir, ...(pathParts.length ? { PATH: pathParts.join(delimiter) } : {}) };
27
+ }
28
+ function configPaths(homeDir) {
29
+ const root = join(homeDir, ".zcode");
30
+ return {
31
+ root,
32
+ community: join(root, "cli", "setting.json"),
33
+ official: join(root, "cli", "config.json"),
34
+ };
35
+ }
36
+ function publicCommand(env) {
37
+ return env.TRELLIS_ZCODE_BIN?.trim() || "zcode";
38
+ }
39
+ function cliFacts(homeDir, env) {
40
+ const command = publicCommand(env);
41
+ const childEnv = zcodeEnv(homeDir, env);
42
+ try {
43
+ const version = execFileSync(command, ["version"], { encoding: "utf-8", timeout: 5_000, env: childEnv }).trim();
44
+ let help;
45
+ let outputFormatSupported = false;
46
+ try {
47
+ help = execFileSync(command, ["--help"], { encoding: "utf-8", timeout: 5_000, env: childEnv });
48
+ }
49
+ catch {
50
+ // A version identity still permits a configuration-only profile.
51
+ }
52
+ try {
53
+ // Some zcode-app-cli builds accept --output-format but omit it from
54
+ // their generated help text. --version never starts a model turn, so
55
+ // it is a safe capability probe for the public argument contract.
56
+ execFileSync(command, ["--output-format", "stream-json", "--version"], { encoding: "utf-8", timeout: 5_000, env: childEnv });
57
+ outputFormatSupported = true;
58
+ }
59
+ catch {
60
+ // Keep the false value; callers then leave execution disabled.
61
+ }
62
+ return { command, version, ...(help ? { help } : {}), outputFormatSupported };
63
+ }
64
+ catch {
65
+ return {};
66
+ }
67
+ }
68
+ export function selectZcodeProfile(homeDir, facts = {}) {
69
+ const paths = configPaths(homeDir);
70
+ const version = facts.version ?? "";
71
+ const supportsExecution = Boolean(facts.command
72
+ && facts.help?.includes("--prompt")
73
+ && facts.help.includes("--resume")
74
+ && (facts.help.includes("--output-format") || facts.outputFormatSupported === true));
75
+ if (/^zcode-app-cli\b/im.test(version) || (existsSync(paths.community) && !existsSync(paths.official))) {
76
+ return {
77
+ kind: "community-cli",
78
+ configPath: paths.community,
79
+ ...(facts.command ? { executable: facts.command } : {}),
80
+ ...(facts.version ? { executableVersion: facts.version } : {}),
81
+ supportsExecution,
82
+ };
83
+ }
84
+ if (facts.command || existsSync(paths.official)) {
85
+ return {
86
+ kind: facts.command ? "official" : "configuration-only",
87
+ configPath: paths.official,
88
+ ...(facts.command ? { executable: facts.command } : {}),
89
+ ...(facts.version ? { executableVersion: facts.version } : {}),
90
+ supportsExecution,
91
+ };
92
+ }
93
+ if (existsSync(paths.root)) {
94
+ return { kind: "configuration-only", configPath: paths.official, supportsExecution: false };
95
+ }
96
+ return undefined;
97
+ }
98
+ export function resolveZcodeProfile(homeDir = homedir(), env = process.env) {
99
+ // A public `zcode` binary is installed system-wide, whereas probes run
100
+ // against an explicit home directory. Do not let the real machine's CLI
101
+ // make an empty sandbox home appear to have ZCode installed; the profile
102
+ // must have local `.zcode` state before any executable is queried.
103
+ if (!existsSync(configPaths(homeDir).root))
104
+ return undefined;
105
+ return selectZcodeProfile(homeDir, cliFacts(homeDir, env));
106
+ }
107
+ export async function probe(homeDir = homedir(), opts = {}) {
108
+ const env = opts.env ?? process.env;
109
+ const profile = resolveZcodeProfile(homeDir, env);
110
+ if (!profile)
111
+ return { agent: "zcode", present: false, skillRoots: [], mcpServers: [], diagnostics: [] };
112
+ const config = readJsonFile(profile.configPath);
113
+ const mcpServers = Object.entries(config?.mcp?.servers ?? {}).map(([name, def]) => ({
114
+ name,
115
+ transport: def.url ? (def.type === "sse" ? "sse" : "http") : "stdio",
116
+ }));
117
+ if (opts.probeMcp) {
118
+ await Promise.all(Object.entries(config?.mcp?.servers ?? {}).map(async ([name, def], index) => {
119
+ if (def.url || !def.command)
120
+ return;
121
+ mcpServers[index].probe = await probeMcpServer({ transport: "stdio", command: def.command, args: def.args }, resolveEnvRefs(def.env, zcodeEnv(homeDir, env)));
122
+ }));
123
+ }
124
+ const skillRoots = [
125
+ scanSkillRoot(join(homeDir, ".zcode", "skills")),
126
+ scanSkillRoot(join(homeDir, ".agents", "skills")),
127
+ ].filter((root) => root !== undefined);
128
+ const diagnostics = [];
129
+ if (!profile.supportsExecution)
130
+ diagnostics.push("ZCode public CLI execution is unavailable; configuration-only management is supported");
131
+ return {
132
+ agent: "zcode",
133
+ present: true,
134
+ ...(profile.executableVersion ? { version: profile.executableVersion } : {}),
135
+ skillRoots,
136
+ mcpServers,
137
+ instructionsFile: pathRef(join(homeDir, ".zcode", "AGENTS.md")),
138
+ diagnostics,
139
+ };
140
+ }
package/dist/sdk.d.ts CHANGED
@@ -11,4 +11,4 @@
11
11
  */
12
12
  export { loadCanonicalSource } from "./core/canonical.js";
13
13
  export { ALL_AGENTS, resolveScope } from "./core/types.js";
14
- export type { AgentId, AgentProfile, CanonicalSource, HubConfig, McpConfig, McpServerDef, MemoryEntry, Scope, SecretsPolicy, SkillRef, Transport, } from "./core/types.js";
14
+ export type { AgentId, AgentProfile, CapabilityDelivery, CanonicalSource, HubConfig, McpConfig, McpRuntimeConfig, McpServerDef, MemoryEntry, Scope, SecretsPolicy, SkillRef, Transport, } from "./core/types.js";