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
@@ -89,8 +89,39 @@ function loadServersYaml(path) {
89
89
  knownHostInjected: parsed.known_host_injected ?? [],
90
90
  hub: parsed.hub,
91
91
  gateway: fromGatewayYaml(parsed.gateway),
92
+ routes: fromRoutesYaml(parsed.routes),
93
+ runtime: fromRuntimeYaml(parsed.runtime),
92
94
  };
93
95
  }
96
+ function fromRuntimeYaml(runtime) {
97
+ if (!runtime?.delivery)
98
+ return undefined;
99
+ const delivery = {};
100
+ for (const [rawAgent, rawDelivery] of Object.entries(runtime.delivery)) {
101
+ if (!ALL_AGENTS.includes(rawAgent))
102
+ continue;
103
+ if (rawDelivery !== "native" && rawDelivery !== "mcp" && rawDelivery !== "both")
104
+ continue;
105
+ delivery[rawAgent] = rawDelivery;
106
+ }
107
+ return Object.keys(delivery).length > 0 ? { delivery } : undefined;
108
+ }
109
+ function fromRoutesYaml(routes) {
110
+ if (!routes)
111
+ return undefined;
112
+ const out = {};
113
+ for (const [rawAgent, rawRoute] of Object.entries(routes)) {
114
+ if (!ALL_AGENTS.includes(rawAgent))
115
+ continue;
116
+ if (!rawRoute?.mode || !["direct", "gateway", "hub"].includes(rawRoute.mode))
117
+ continue;
118
+ out[rawAgent] = {
119
+ mode: rawRoute.mode,
120
+ ...(rawRoute.servers ? { servers: rawRoute.servers } : {}),
121
+ };
122
+ }
123
+ return Object.keys(out).length > 0 ? out : undefined;
124
+ }
94
125
  /**
95
126
  * A `gateway:` block with no `enabled` key reads as off, not as on — the
96
127
  * only safe default for a field whose whole effect is to stop writing the
@@ -137,7 +168,15 @@ function forceBlockStyle(node) {
137
168
  node.flow = false;
138
169
  }
139
170
  }
140
- export function upsertServerYaml(path, name, def) {
171
+ function persistText(path, content, backup) {
172
+ if (existsSync(path) && readFileSync(path, "utf-8") === content)
173
+ return;
174
+ if (backup)
175
+ backup.writeFile(path, content);
176
+ else
177
+ writeFileSync(path, content);
178
+ }
179
+ export function upsertServerYaml(path, name, def, backup) {
141
180
  if (!existsSync(path)) {
142
181
  return { ok: false, error: `${path} does not exist — run \`trellis init\` first` };
143
182
  }
@@ -151,12 +190,12 @@ export function upsertServerYaml(path, name, def) {
151
190
  doc.setIn(["servers", name], toServerDefYaml(def));
152
191
  forceBlockStyle(doc.get("servers", true));
153
192
  forceBlockStyle(doc.getIn(["servers", name], true));
154
- writeFileSync(path, doc.toString());
193
+ persistText(path, doc.toString(), backup);
155
194
  return { ok: true };
156
195
  }
157
196
  /** Inverse of `upsertServerYaml` — same preservation guarantee, same
158
197
  * refusal posture on a missing/unparseable file. */
159
- export function removeServerYaml(path, name) {
198
+ export function removeServerYaml(path, name, backup) {
160
199
  if (!existsSync(path)) {
161
200
  return { ok: false, error: `${path} does not exist — run \`trellis init\` first` };
162
201
  }
@@ -168,7 +207,7 @@ export function removeServerYaml(path, name) {
168
207
  return { ok: false, error: `could not parse ${path}: ${err instanceof Error ? err.message : String(err)}` };
169
208
  }
170
209
  doc.deleteIn(["servers", name]);
171
- writeFileSync(path, doc.toString());
210
+ persistText(path, doc.toString(), backup);
172
211
  return { ok: true };
173
212
  }
174
213
  /**
@@ -181,7 +220,7 @@ export function removeServerYaml(path, name) {
181
220
  * starter file). Selecting one mode always clears the other two
182
221
  * (design.md D3) — never left for the caller to remember.
183
222
  */
184
- export function writeMcpModeYaml(path, mode) {
223
+ export function writeMcpModeYaml(path, mode, backup) {
185
224
  if (!existsSync(path)) {
186
225
  return { ok: false, error: `${path} does not exist — run \`trellis init\` first` };
187
226
  }
@@ -214,7 +253,56 @@ export function writeMcpModeYaml(path, mode) {
214
253
  forceBlockStyle(doc.get("gateway", true));
215
254
  break;
216
255
  }
217
- writeFileSync(path, doc.toString());
256
+ persistText(path, doc.toString(), backup);
257
+ return { ok: true };
258
+ }
259
+ /** Writes explicit per-agent routes while preserving legacy hub/gateway
260
+ * shorthand. An empty route map removes the optional key. */
261
+ export function writeMcpRoutesYaml(path, routes, backup) {
262
+ if (!existsSync(path)) {
263
+ return { ok: false, error: `${path} does not exist — run \`trellis init\` first` };
264
+ }
265
+ let doc;
266
+ try {
267
+ doc = parseDocument(readFileSync(path, "utf-8"));
268
+ }
269
+ catch (err) {
270
+ return { ok: false, error: `could not parse ${path}: ${err instanceof Error ? err.message : String(err)}` };
271
+ }
272
+ const serialized = Object.fromEntries(Object.entries(routes).map(([agent, route]) => [agent, { mode: route.mode, ...(route.servers ? { servers: route.servers } : {}) }]));
273
+ if (Object.keys(serialized).length === 0) {
274
+ doc.delete("routes");
275
+ }
276
+ else {
277
+ doc.set("routes", serialized);
278
+ forceBlockStyle(doc.get("routes", true));
279
+ }
280
+ persistText(path, doc.toString(), backup);
281
+ return { ok: true };
282
+ }
283
+ /** Writes per-agent capability delivery preferences into servers.yaml.
284
+ * Omitted entries continue to use the native default. */
285
+ export function writeMcpRuntimeDeliveryYaml(path, delivery, backup) {
286
+ if (!existsSync(path)) {
287
+ return { ok: false, error: path + " does not exist — run trellis init first" };
288
+ }
289
+ let doc;
290
+ try {
291
+ doc = parseDocument(readFileSync(path, "utf-8"));
292
+ }
293
+ catch (err) {
294
+ return { ok: false, error: `could not parse ${path}: ${err instanceof Error ? err.message : String(err)}` };
295
+ }
296
+ const serialized = Object.fromEntries(Object.entries(delivery).map(([agent, mode]) => [agent, mode]));
297
+ if (Object.keys(serialized).length === 0) {
298
+ doc.delete("runtime");
299
+ }
300
+ else {
301
+ doc.setIn(["runtime", "delivery"], serialized);
302
+ forceBlockStyle(doc.get("runtime", true));
303
+ forceBlockStyle(doc.getIn(["runtime", "delivery"], true));
304
+ }
305
+ persistText(path, doc.toString(), backup);
218
306
  return { ok: true };
219
307
  }
220
308
  function loadSecretsPolicyYaml(path, homeDir) {
@@ -240,7 +328,7 @@ function loadSecretsPolicyYaml(path, homeDir) {
240
328
  * `varName` to `allowed_vars` only if not already present (dedup, same
241
329
  * "already there is a no-op" rule every other Trellis writer follows).
242
330
  */
243
- export function writeSecretsPolicyExtraction(path, extraction) {
331
+ export function writeSecretsPolicyExtraction(path, extraction, backup) {
244
332
  if (!existsSync(path)) {
245
333
  return { ok: false, error: `${path} does not exist — run \`trellis init\` first` };
246
334
  }
@@ -262,7 +350,7 @@ export function writeSecretsPolicyExtraction(path, extraction) {
262
350
  doc.set("allowed_vars", [...currentAllowedVars, extraction.varName]);
263
351
  forceBlockStyle(doc.get("allowed_vars", true));
264
352
  }
265
- writeFileSync(path, doc.toString());
353
+ persistText(path, doc.toString(), backup);
266
354
  return { ok: true };
267
355
  }
268
356
  /**
@@ -275,13 +363,13 @@ export function writeSecretsPolicyExtraction(path, extraction) {
275
363
  * init`'s own bootstrap, so a machine that never extracts a secret never
276
364
  * gains this file at all.
277
365
  */
278
- export function ensureGitignoreEntry(gitignorePath, line) {
366
+ export function ensureGitignoreEntry(gitignorePath, line, backup) {
279
367
  const existing = existsSync(gitignorePath) ? readFileSync(gitignorePath, "utf-8") : "";
280
368
  const lines = existing.split("\n").map((l) => l.trim());
281
369
  if (lines.includes(line))
282
370
  return;
283
371
  const separator = existing.length > 0 && !existing.endsWith("\n") ? "\n" : "";
284
- writeFileSync(gitignorePath, `${existing}${separator}${line}\n`);
372
+ persistText(gitignorePath, `${existing}${separator}${line}\n`, backup);
285
373
  }
286
374
  const SHELL_ENV_SOURCE_MARKER = "# >>> trellis mcp secrets >>>";
287
375
  const SHELL_ENV_SOURCE_END_MARKER = "# <<< trellis mcp secrets <<<";
@@ -297,17 +385,17 @@ const SHELL_ENV_SOURCE_END_MARKER = "# <<< trellis mcp secrets <<<";
297
385
  * lines `parseDotenv` already expects, so that format never needs an
298
386
  * `export` prefix of its own.
299
387
  */
300
- export function ensureShellEnvSource(rcPath, envFilePath) {
388
+ export function ensureShellEnvSource(rcPath, envFilePath, backup) {
301
389
  const existing = existsSync(rcPath) ? readFileSync(rcPath, "utf-8") : "";
302
390
  if (existing.includes(SHELL_ENV_SOURCE_MARKER))
303
391
  return;
304
392
  const separator = existing.length > 0 && !existing.endsWith("\n") ? "\n" : "";
305
393
  const block = `${SHELL_ENV_SOURCE_MARKER}\nif [ -f "${envFilePath}" ]; then\n set -a\n source "${envFilePath}"\n set +a\nfi\n${SHELL_ENV_SOURCE_END_MARKER}\n`;
306
394
  mkdirSync(dirname(rcPath), { recursive: true });
307
- writeFileSync(rcPath, `${existing}${separator}${block}`);
395
+ persistText(rcPath, `${existing}${separator}${block}`, backup);
308
396
  }
309
397
  /** `undefined` if the name has no entry in scope.yaml's map — "shared with
310
- * all four agents," the default. A recognized but empty list is left as
398
+ * all managed agents by default. A recognized but empty list is left as
311
399
  * authored (an explicitly agent-less scope), not coerced to "all". */
312
400
  /** Missing file and `agents: []` both resolve to `[]` — zero managed
313
401
  * agents (D1), never "everyone." An unrecognized id is dropped with a
@@ -0,0 +1,45 @@
1
+ import type { AgentId, CapabilityDelivery, CanonicalSource, McpRouteMode } from "./types.js";
2
+ export type NameSelection = "all" | "none" | string[];
3
+ export interface CapabilitySelection {
4
+ skills: NameSelection;
5
+ mcpServers: NameSelection;
6
+ memories: NameSelection;
7
+ memoryMigration: "all" | "none";
8
+ mcpRoutes: Partial<Record<AgentId, {
9
+ mode: McpRouteMode;
10
+ servers?: string[];
11
+ }>>;
12
+ runtimeDelivery: Partial<Record<AgentId, CapabilityDelivery>>;
13
+ }
14
+ export interface CapabilityItem {
15
+ name: string;
16
+ displayName: string;
17
+ fingerprint?: string;
18
+ status: "new" | "unchanged" | "changed" | "unsupported";
19
+ detail?: string;
20
+ }
21
+ export interface UnsupportedCapabilitySource {
22
+ name: string;
23
+ detail: string;
24
+ }
25
+ export interface CapabilityInventory {
26
+ skills: CapabilityItem[];
27
+ mcpServers: CapabilityItem[];
28
+ canonicalMemories: CapabilityItem[];
29
+ nativeMemory: UnsupportedCapabilitySource[];
30
+ }
31
+ export type SelectionFileResult = {
32
+ ok: true;
33
+ selection: CapabilitySelection;
34
+ } | {
35
+ ok: false;
36
+ error: string;
37
+ };
38
+ export declare function parseCapabilitySelectionFile(path: string): SelectionFileResult;
39
+ export declare function defaultCapabilitySelection(): CapabilitySelection;
40
+ export declare function resolveSelectedNames(selection: NameSelection, available: readonly string[]): string[];
41
+ export declare function selectionContains(selection: NameSelection, name: string): boolean;
42
+ export declare function buildCapabilityInventory(source: {
43
+ skillNames: readonly string[];
44
+ mcpServerNames: readonly string[];
45
+ }, canonical: Pick<CanonicalSource, "skills" | "mcp" | "memories">, nativeMemory?: UnsupportedCapabilitySource[]): CapabilityInventory;
@@ -0,0 +1,124 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { parse as parseYaml } from "yaml";
3
+ import { ALL_AGENTS } from "./types.js";
4
+ const ALL_SELECTION = {
5
+ skills: "all",
6
+ mcpServers: "all",
7
+ memories: "all",
8
+ memoryMigration: "all",
9
+ mcpRoutes: {},
10
+ runtimeDelivery: {},
11
+ };
12
+ function parseNameSelection(value, field) {
13
+ if (value === undefined)
14
+ return "all";
15
+ if (value === "all" || value === "none")
16
+ return value;
17
+ if (Array.isArray(value) && value.every((item) => typeof item === "string" && item.length > 0)) {
18
+ return [...new Set(value)];
19
+ }
20
+ throw new Error(`${field} must be "all", "none", or a list of names`);
21
+ }
22
+ function parseRoutes(value) {
23
+ if (value === undefined)
24
+ return {};
25
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
26
+ throw new Error("mcp_routes must be a map of agent ids to route definitions");
27
+ }
28
+ const routes = {};
29
+ for (const [rawAgent, rawRoute] of Object.entries(value)) {
30
+ if (!ALL_AGENTS.includes(rawAgent)) {
31
+ throw new Error(`mcp_routes contains unknown agent "${rawAgent}"`);
32
+ }
33
+ if (typeof rawRoute !== "object" || rawRoute === null || Array.isArray(rawRoute)) {
34
+ throw new Error(`mcp_routes.${rawAgent} must be a route object`);
35
+ }
36
+ const route = rawRoute;
37
+ if (route.mode !== "direct" && route.mode !== "gateway" && route.mode !== "hub") {
38
+ throw new Error(`mcp_routes.${rawAgent}.mode must be direct, gateway, or hub`);
39
+ }
40
+ if (route.servers !== undefined && (!Array.isArray(route.servers) || !route.servers.every((item) => typeof item === "string" && item.length > 0))) {
41
+ throw new Error(`mcp_routes.${rawAgent}.servers must be a list of names`);
42
+ }
43
+ routes[rawAgent] = {
44
+ mode: route.mode,
45
+ ...(route.servers ? { servers: [...new Set(route.servers)] } : {}),
46
+ };
47
+ }
48
+ return routes;
49
+ }
50
+ function parseRuntimeDelivery(value) {
51
+ if (value === undefined)
52
+ return {};
53
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
54
+ throw new Error("runtime_delivery must be a map of agent ids to native, mcp, or both");
55
+ }
56
+ const delivery = {};
57
+ for (const [rawAgent, rawMode] of Object.entries(value)) {
58
+ if (!ALL_AGENTS.includes(rawAgent)) {
59
+ throw new Error(`runtime_delivery contains unknown agent "${rawAgent}"`);
60
+ }
61
+ if (rawMode !== "native" && rawMode !== "mcp" && rawMode !== "both") {
62
+ throw new Error(`runtime_delivery.${rawAgent} must be native, mcp, or both`);
63
+ }
64
+ delivery[rawAgent] = rawMode;
65
+ }
66
+ return delivery;
67
+ }
68
+ export function parseCapabilitySelectionFile(path) {
69
+ if (!existsSync(path))
70
+ return { ok: false, error: `selection file does not exist: ${path}` };
71
+ try {
72
+ const parsed = (parseYaml(readFileSync(path, "utf8")) ?? {});
73
+ return {
74
+ ok: true,
75
+ selection: {
76
+ skills: parseNameSelection(parsed.skills, "skills"),
77
+ mcpServers: parseNameSelection(parsed.mcp_servers, "mcp_servers"),
78
+ memories: parseNameSelection(parsed.memories, "memories"),
79
+ memoryMigration: parsed.memory_migration === undefined || parsed.memory_migration === "all" ? "all" : parsed.memory_migration === "none" ? "none" : (() => { throw new Error('memory_migration must be "all" or "none"'); })(),
80
+ mcpRoutes: parseRoutes(parsed.mcp_routes),
81
+ runtimeDelivery: parseRuntimeDelivery(parsed.runtime_delivery),
82
+ },
83
+ };
84
+ }
85
+ catch (err) {
86
+ return { ok: false, error: `could not parse selection file ${path}: ${err instanceof Error ? err.message : String(err)}` };
87
+ }
88
+ }
89
+ export function defaultCapabilitySelection() {
90
+ return { ...ALL_SELECTION, mcpRoutes: {}, runtimeDelivery: {} };
91
+ }
92
+ export function resolveSelectedNames(selection, available) {
93
+ if (selection === "all")
94
+ return [...available];
95
+ if (selection === "none")
96
+ return [];
97
+ const availableSet = new Set(available);
98
+ return [...new Set(selection.filter((name) => availableSet.has(name)))];
99
+ }
100
+ export function selectionContains(selection, name) {
101
+ return selection === "all" || (selection !== "none" && selection.includes(name));
102
+ }
103
+ export function buildCapabilityInventory(source, canonical, nativeMemory = []) {
104
+ const canonicalSkills = new Set(canonical.skills.map((skill) => skill.name));
105
+ const canonicalMcp = new Set(Object.keys(canonical.mcp.servers));
106
+ return {
107
+ skills: source.skillNames.map((name) => ({
108
+ name,
109
+ displayName: name,
110
+ status: canonicalSkills.has(name) ? "unchanged" : "new",
111
+ })),
112
+ mcpServers: source.mcpServerNames.map((name) => ({
113
+ name,
114
+ displayName: name,
115
+ status: canonicalMcp.has(name) ? "unchanged" : "new",
116
+ })),
117
+ canonicalMemories: canonical.memories.map((memory) => ({
118
+ name: memory.name,
119
+ displayName: memory.name,
120
+ status: "unchanged",
121
+ })),
122
+ nativeMemory,
123
+ };
124
+ }
@@ -5,11 +5,12 @@
5
5
  * files on disk are its serialization, not the other way around.
6
6
  */
7
7
  export type Transport = "stdio" | "http" | "sse";
8
- export type AgentId = "claude-code" | "codex" | "kiro" | "pi";
8
+ export type McpAuthMode = "oauth";
9
+ export type AgentId = "claude-code" | "codex" | "kiro" | "pi" | "kimi-code" | "zcode";
9
10
  export declare const ALL_AGENTS: readonly AgentId[];
10
11
  /**
11
12
  * Every scopable item (skill, subagent, memory entry, MCP server) defaults
12
- * to "all four agents" when `scope` is omitted — sharing everywhere is the
13
+ * to all managed agents when `scope` is omitted — sharing everywhere is the
13
14
  * common case Trellis exists for; restricting to specific agents is the
14
15
  * exception and must be declared explicitly. See docs/architecture.md
15
16
  * "Private / agent-specific capabilities".
@@ -26,6 +27,9 @@ export type Scope = AgentId[] | undefined;
26
27
  export declare function resolveScope(scope: Scope, managedAgents: readonly AgentId[]): readonly AgentId[];
27
28
  export interface McpServerDef {
28
29
  transport: Transport;
30
+ /** Explicit authorization classification. Absence means ordinary MCP;
31
+ * Trellis never infers OAuth from a URL or a transient 401. */
32
+ auth?: McpAuthMode;
29
33
  /** stdio only */
30
34
  command?: string;
31
35
  args?: string[];
@@ -109,6 +113,18 @@ export interface GatewayConfig {
109
113
  */
110
114
  agents?: AgentId[];
111
115
  }
116
+ export type McpRouteMode = "direct" | "gateway" | "hub";
117
+ export interface McpRoute {
118
+ mode: McpRouteMode;
119
+ /** Omit to expose every eligible canonical server for this agent. */
120
+ servers?: string[];
121
+ }
122
+ export type CapabilityDelivery = "native" | "mcp" | "both";
123
+ export interface McpRuntimeConfig {
124
+ /** Per-agent delivery for Trellis-owned capabilities and upstream MCP.
125
+ * Omitted means native, preserving the existing adapter behavior. */
126
+ delivery?: Partial<Record<AgentId, CapabilityDelivery>>;
127
+ }
112
128
  export interface McpConfig {
113
129
  servers: Record<string, McpServerDef>;
114
130
  /**
@@ -127,7 +143,14 @@ export interface McpConfig {
127
143
  * two mean different things and may both be set, in which case gateway
128
144
  * wins per agent (trellis-mcp-gateway-hosting design.md D5/D6). */
129
145
  gateway?: GatewayConfig;
146
+ /** Optional per-agent route overrides. Explicit routes take precedence
147
+ * over the legacy hub/gateway shorthand for the named agent. */
148
+ routes?: Partial<Record<AgentId, McpRoute>>;
149
+ /** Optional runtime delivery preferences. */
150
+ runtime?: McpRuntimeConfig;
130
151
  }
152
+ export declare function capabilityDeliveryForAgent(agentId: AgentId, mcp: McpConfig): CapabilityDelivery;
153
+ export declare function usesNativeCapabilityDelivery(agentId: AgentId, mcp: McpConfig): boolean;
131
154
  export interface SkillRef {
132
155
  name: string;
133
156
  /** Absolute path to the skill's directory. Must contain `SKILL.md` — the
@@ -9,6 +9,8 @@ export const ALL_AGENTS = [
9
9
  "codex",
10
10
  "kiro",
11
11
  "pi",
12
+ "kimi-code",
13
+ "zcode",
12
14
  ];
13
15
  /**
14
16
  * `managedAgents` is the hard outer boundary (trellis-managed-agents
@@ -22,3 +24,9 @@ export function resolveScope(scope, managedAgents) {
22
24
  const candidates = scope ?? managedAgents;
23
25
  return candidates.filter((id) => managedAgents.includes(id));
24
26
  }
27
+ export function capabilityDeliveryForAgent(agentId, mcp) {
28
+ return mcp.runtime?.delivery?.[agentId] ?? "native";
29
+ }
30
+ export function usesNativeCapabilityDelivery(agentId, mcp) {
31
+ return capabilityDeliveryForAgent(agentId, mcp) !== "mcp";
32
+ }
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Cross-Agent delegation (trellis-agent-bridge): lets a managed Agent call
3
+ * another managed Agent's own verified non-interactive/headless mode as a
4
+ * one-shot subprocess call, so each Agent's strengths can be used without a
5
+ * central orchestrator or any cross-machine protocol.
6
+ *
7
+ * Configuration lives at `~/.trellis/mcp/agent-bridge.yaml`, sibling to
8
+ * `servers.yaml`, and is fully optional — its absence means zero behavior
9
+ * change (design.md Migration Plan).
10
+ */
11
+ import { type AgentId } from "../core/types.js";
12
+ export type AgentBridgeOutputFormat = "text" | "json" | "stream-json";
13
+ export type StreamProtocol = "claude" | "zcode";
14
+ export interface AgentBridgeTargetConfig {
15
+ /** Binary to spawn, e.g. "codex", "claude", "pi", "kimi". */
16
+ command: string;
17
+ /** Argv template for a fresh call. One element may be the literal
18
+ * placeholder `"{prompt}"`, substituted with the caller's prompt (and
19
+ * persona, if the target has no dedicated persona flag — see
20
+ * `PERSONA_PLACEHOLDER`) at call time — covers a trailing positional
21
+ * prompt (Codex, Claude Code, pi) and a flag-value prompt (Kimi Code's
22
+ * `-p, --prompt <prompt>`) with the same shape. */
23
+ args: string[];
24
+ /** Argv template used instead of `args` when the caller supplies a
25
+ * `sessionId` to resume — must reference `"{sessionId}"`. Omitting this
26
+ * means the target does not support resuming a prior session; a call
27
+ * that supplies `sessionId` against such a target fails with a clear
28
+ * error rather than silently starting a fresh session. */
29
+ resumeArgs?: string[];
30
+ /** How to interpret stdout. Omit for plain text. */
31
+ outputFormat?: AgentBridgeOutputFormat;
32
+ /** Selects a verified event envelope for stream-json output. Omit for
33
+ * Claude-compatible streams, which remains the existing default. */
34
+ streamProtocol?: StreamProtocol;
35
+ timeoutMs?: number;
36
+ /** Free-text, informational only — surfaced in the exposed tool's
37
+ * description so a caller can judge fit; never validated against a
38
+ * taxonomy. */
39
+ tags?: string[];
40
+ /** Default persona/role text applied to every call to this target
41
+ * unless a call overrides it. Substituted into `"{persona}"` when the
42
+ * chosen argv template has that placeholder; otherwise prepended to the
43
+ * prompt as a framing line, so every target gets persona support even
44
+ * without a native system-prompt flag. */
45
+ persona?: string;
46
+ }
47
+ export interface AgentBridgeConfig {
48
+ targets: Partial<Record<AgentId, AgentBridgeTargetConfig>>;
49
+ /** Maximum delegation chain depth before a call is refused, to bound
50
+ * A→B→A (or longer) cycles. Defaults to `DEFAULT_MAX_DELEGATION_DEPTH`. */
51
+ maxDepth?: number;
52
+ }
53
+ export declare const DEFAULT_DELEGATION_TIMEOUT_MS = 120000;
54
+ export declare const DEFAULT_MAX_DELEGATION_DEPTH = 2;
55
+ /** Carries the current delegation depth down the real process tree — the
56
+ * gateway that receives a delegated call inherits this from its spawning
57
+ * shell, so depth travels with the chain itself without a live shared
58
+ * registry (design.md Decision 3). */
59
+ export declare const DELEGATION_DEPTH_ENV = "TRELLIS_DELEGATION_DEPTH";
60
+ export declare function agentBridgePath(homeDir: string): string;
61
+ /** Reads the current chain depth from an environment map (defaults to
62
+ * `process.env`, injectable for tests). Anything absent or malformed
63
+ * reads as depth 0 — the safe "not part of a chain yet" default. */
64
+ export declare function readDelegationDepth(env?: NodeJS.ProcessEnv): number;
65
+ export declare function loadAgentBridgeConfig(homeDir: string): AgentBridgeConfig;
66
+ export interface DelegatedCallResult {
67
+ status: "completed" | "failed" | "timeout";
68
+ output: string;
69
+ durationMs: number;
70
+ targetAgent: AgentId;
71
+ /** Present when the target reported one (best-effort extraction from
72
+ * `json`/`stream-json` output). Pass back as `sessionId` in a later
73
+ * call to continue this exact conversation, if the target has
74
+ * `resumeArgs` configured. */
75
+ sessionId?: string;
76
+ }
77
+ export interface RunDelegatedCallOptions {
78
+ cwd?: string;
79
+ timeoutMs?: number;
80
+ /** Overrides the target's default `persona` for this call only. */
81
+ persona?: string;
82
+ /** Resume a prior conversation instead of starting a fresh one.
83
+ * Requires the target to have `resumeArgs` configured. */
84
+ sessionId?: string;
85
+ /** The chain depth *before* this call (0 for a call that isn't itself
86
+ * part of a delegation chain). The spawned child sees `depth + 1`. */
87
+ depth?: number;
88
+ }
89
+ /** Spawns the target's verified non-interactive invocation, enforces
90
+ * `timeoutMs` with SIGTERM-then-SIGKILL escalation, and normalizes the
91
+ * result into one envelope regardless of which CLI is underneath. Does
92
+ * NOT itself enforce a depth ceiling — refusing at the limit is the
93
+ * caller's job (AgentBridgeProvider), since only it knows the configured
94
+ * `maxDepth`; this function only propagates whatever depth it's given. */
95
+ export declare function runDelegatedCall(targetAgent: AgentId, target: AgentBridgeTargetConfig, prompt: string, opts?: RunDelegatedCallOptions): Promise<DelegatedCallResult>;
96
+ /** Best-effort structured interpretation of one line of a `stream-json`
97
+ * target's stdout, covering the four shapes documented by the community
98
+ * for Claude Code's non-interactive stream-json output (there is no
99
+ * official Anthropic schema — see upstream issue #24612): a `system/init`
100
+ * line, an `assistant` message carrying text or a `tool_use` block, a
101
+ * `user` message carrying a `tool_result` block, and the final `result`
102
+ * line. Anything that doesn't parse as JSON, or parses but doesn't match
103
+ * one of these shapes, returns `undefined` — the caller falls back to
104
+ * displaying the raw line rather than guessing. */
105
+ export type ParsedStreamEvent = {
106
+ kind: "init";
107
+ sessionId?: string;
108
+ } | {
109
+ kind: "text-delta";
110
+ text: string;
111
+ } | {
112
+ kind: "tool-call";
113
+ toolCallId: string;
114
+ name: string;
115
+ input: unknown;
116
+ } | {
117
+ kind: "tool-result";
118
+ toolCallId: string;
119
+ output: unknown;
120
+ } | {
121
+ kind: "final";
122
+ output: string;
123
+ sessionId?: string;
124
+ protocol?: "zcode";
125
+ };
126
+ export declare function tryParseClaudeStreamJsonLine(line: string): ParsedStreamEvent | undefined;
127
+ /** ZCode's documented headless result envelope is deliberately distinct from
128
+ * Claude-compatible streams: `{ type: "result", response, sessionId }`.
129
+ * Intermediate ZCode protocol events evolve with the runtime, so unknown
130
+ * records remain raw chunks rather than being guessed into false tool/text
131
+ * events. */
132
+ export declare function tryParseZcodeStreamJsonLine(line: string): ParsedStreamEvent | undefined;
133
+ export interface StreamChunk {
134
+ /** Raw text as received from the child, one line (no trailing newline). */
135
+ raw: string;
136
+ /** Present only when `outputFormat: "stream-json"` and the line matched
137
+ * a recognized Claude Code shape — see `tryParseClaudeStreamJsonLine`. */
138
+ parsed?: ParsedStreamEvent;
139
+ }
140
+ export interface DelegatedStreamResult {
141
+ status: "completed" | "failed" | "timeout" | "cancelled";
142
+ output: string;
143
+ durationMs: number;
144
+ /** Chat targets are identified by an arbitrary string id (`chat-agents.yaml`
145
+ * has no `AgentId` constraint — see `chatAgents.ts`), unlike
146
+ * `DelegatedCallResult.targetAgent` which is always a real managed Agent. */
147
+ targetAgent: string;
148
+ sessionId?: string;
149
+ }
150
+ export interface RunDelegatedCallStreamingOptions extends Omit<RunDelegatedCallOptions, "depth"> {
151
+ /** Called once per line of stdout, as it arrives — not batched until the
152
+ * process exits, unlike `runDelegatedCall`. */
153
+ onChunk: (chunk: StreamChunk) => void;
154
+ /** The chain depth before this call, same meaning as
155
+ * `RunDelegatedCallOptions.depth`. */
156
+ depth?: number;
157
+ /** Aborting triggers the same SIGTERM→SIGKILL escalation as a timeout;
158
+ * the returned result has `status: "cancelled"` instead of `"timeout"`. */
159
+ signal?: AbortSignal;
160
+ }
161
+ /** Streaming counterpart to `runDelegatedCall`: same argv-building,
162
+ * timeout escalation, and persona/session handling, but emits `onChunk`
163
+ * for every line of stdout as it arrives instead of buffering until the
164
+ * process exits, and supports cooperative cancellation via `signal`. Takes
165
+ * a plain `string` target id (not `AgentId`) so it can serve both a future
166
+ * streaming MCP delegation tool and today's GUI chat feature, whose
167
+ * targets come from `chat-agents.yaml` and are not required to be one of
168
+ * the fully-managed Agents in `ALL_AGENTS`. */
169
+ export declare function runDelegatedCallStreaming(targetAgent: string, target: AgentBridgeTargetConfig, prompt: string, opts: RunDelegatedCallStreamingOptions): Promise<DelegatedStreamResult>;