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
package/dist/cli.js CHANGED
@@ -9,22 +9,33 @@ import { runInit } from "./commands/init.js";
9
9
  import { runMigrate } from "./commands/migrate.js";
10
10
  import { runOnboard } from "./commands/onboard.js";
11
11
  import { runSync } from "./commands/sync.js";
12
- import { runMcpSync, runMcpList, runMcpAdd, runMcpRemove, parseMcpAddArgs } from "./commands/mcp.js";
13
- import { parseMcpGatewayArgs, runMcpGateway } from "./commands/mcpGateway.js";
12
+ import { runMcpSync, runMcpList, runMcpAdd, runMcpRemove, runMcpSetAuth, parseMcpAddArgs } from "./commands/mcp.js";
13
+ import { runMcpImport } from "./commands/mcpImport.js";
14
+ import { parseMcpGatewayArgs, runMcpGateway, runMcpRuntime } from "./commands/mcpGateway.js";
14
15
  import { runMcpAuth } from "./commands/mcpAuth.js";
15
16
  import { runSecretsAudit } from "./commands/secretsAudit.js";
16
17
  import { runRollback } from "./commands/rollback.js";
17
- import { runSkillList, runSkillAdd, runSkillRemove } from "./commands/skill.js";
18
- import { runMemoryExtraction, runMemorySync } from "./commands/memory.js";
18
+ import { runSkillList, runSkillAdd, runSkillRemove, runSkillUpdateBuiltin } from "./commands/skill.js";
19
+ import { collectMemoryList, runMemoryExtraction, runMemorySync } from "./commands/memory.js";
20
+ import { parseManageArgs, runManage } from "./commands/manage.js";
21
+ import { runKimi } from "./commands/kimi.js";
22
+ import { TRELLIS_VERSION } from "./lib/cliMetadata.js";
19
23
  import { parseSyncArgs } from "./lib/syncArgs.js";
20
- const KNOWN_COMMANDS = ["onboard", "init", "migrate", "doctor", "sync", "mcp", "mcp-gateway", "skill", "memory", "secrets", "rollback"];
24
+ const KNOWN_COMMANDS = ["onboard", "init", "migrate", "doctor", "sync", "mcp", "mcp-gateway", "mcp-runtime", "skill", "memory", "manage", "kimi", "secrets", "rollback"];
21
25
  function printUsage() {
22
26
  console.log(`trellis - a single source of capability for every coding agent
23
27
 
24
28
  Usage:
25
29
  trellis <command>
30
+ trellis --version
31
+ trellis --help
32
+
33
+ Options:
34
+ -v, --version print the installed Trellis version
35
+ -h, --help show this help
26
36
 
27
37
  Commands:
38
+ help Show this help
28
39
  onboard Guided flow: init -> detect agents -> pick a migration source ->
29
40
  pick which agents to manage -> migrate -> sync -> mcp sync ->
30
41
  secrets audit, in one command. Source (read from) and managed
@@ -39,15 +50,21 @@ Commands:
39
50
  (required with no terminal to prompt
40
51
  in, e.g. --json)
41
52
  --mcp-mode <direct|hub|gateway>
42
- change the MCP mode; omit to leave
43
- whatever's already configured
44
- untouched (never prompted)
45
- --hub-url <url> required with --mcp-mode hub
53
+ direct = Agent 分别直连;gateway =
54
+ Trellis 本机统一托管(推荐);hub =
55
+ 连接已有的外部 MCP Hub
56
+ --hub-url <url> required with --mcp-mode hub; Trellis
57
+ does not deploy an external Hub
46
58
  --gateway-agents <ids>
47
59
  optional with --mcp-mode gateway;
48
60
  omit for every managed agent
49
61
  --memory <on|off> enable/disable the shared memory MCP
50
62
  server; omit to leave it untouched
63
+ --memory-migrate <on|off>
64
+ import supported native Agent memory into
65
+ canonical; omit to leave it untouched
66
+ --selection <file> item-level YAML/JSON selection for skills,
67
+ MCP servers, memories, and per-agent routes
51
68
  --dry-run preview the whole flow, write nothing
52
69
  --json machine-readable output, no report text
53
70
  init Create ~/.trellis/ with a minimal valid skeleton if missing
@@ -55,12 +72,13 @@ Commands:
55
72
  missing) and prints which agents are present
56
73
  --json machine-readable output, no report text
57
74
  migrate --from <agent>
58
- Import an existing agent's real skills/instructions/MCP
75
+ Import an existing agent's real skills/instructions/MCP/memory
59
76
  servers into canonical source (claude-code | codex | kiro |
60
77
  pi — pi has no static MCP config, mcp migrate-in is a no-op
61
78
  for it). Never overwrites differing content — reports a
62
79
  conflict instead.
63
- --only skills|instructions|mcp restrict to one category
80
+ --only skills|instructions|mcp|memory
81
+ restrict to one category
64
82
  --dry-run preview the plan, write nothing
65
83
  --json machine-readable output, no report text
66
84
  doctor Scan Claude Code / Codex / Kiro / pi for drift
@@ -83,12 +101,22 @@ Commands:
83
101
  --json machine-readable output, no report text
84
102
  mcp add <name> --transport stdio|http|sse ...
85
103
  Add a canonical MCP server (refuses on an existing name,
86
- no overwrite): --command <cmd> [--args a,b] (stdio) or
87
- --url <url> (http/sse); [--headers k=v,...]
88
- [--env NAME,...] [--static-env k=v,...] [--agents id,...]
89
- [--enabled true|false]
90
- --dry-run preview the plan, write nothing
91
- --json machine-readable output, no report text
104
+ no overwrite): --command <cmd> [--args a,b] (stdio) or
105
+ --url <url> (http/sse); [--headers k=v,...]
106
+ [--auth oauth] [--env NAME,...] [--static-env k=v,...] [--agents id,...]
107
+ [--enabled true|false]
108
+ --dry-run preview the plan, write nothing
109
+ --json machine-readable output, no report text
110
+ mcp import <json-file>
111
+ Import a standard mcpServers JSON export without changing the
112
+ source; extracts credential env values into the ignored local
113
+ secret file, de-duplicates, and reports conflicts
114
+ --dry-run preview without writing
115
+ --json machine-readable output, no report text
116
+ mcp set <name> --auth oauth|none
117
+ Set or clear explicit OAuth classification; canonical only
118
+ --dry-run preview the plan, write nothing
119
+ --json machine-readable output, no report text
92
120
  mcp auth <server-name>
93
121
  Authorize a remote (http/sse) MCP server that uses OAuth —
94
122
  opens a browser once, stores the result 0600 under
@@ -97,9 +125,14 @@ Commands:
97
125
  refreshes silently on its own and never prompts.
98
126
  --force re-authorize even if the stored token is valid
99
127
  --json machine-readable output, no report text
128
+ mcp-runtime --agent <agent>
129
+ Internal MCP edge exposing Trellis providers and selected
130
+ upstream capabilities; existing mcp-gateway configs remain valid
131
+ as a compatibility alias
100
132
  mcp remove <name>
101
- Remove a canonical MCP server (canonical-side only — does
102
- not touch any agent's already-synced native config)
133
+ Remove a canonical MCP server, then run the same sync as
134
+ mcp sync so every managed agent's Trellis-owned entry for
135
+ it is removed too
103
136
  --dry-run preview the plan, write nothing
104
137
  --json machine-readable output, no report text
105
138
  skill list
@@ -111,6 +144,11 @@ Commands:
111
144
  --dry-run preview the plan, write nothing
112
145
  --json machine-readable output, no report text
113
146
  skill remove <name>
147
+ skill update-builtin
148
+ Refresh the package-owned trellis-runtime Skill in canonical
149
+ source; existing native symlinks see the update
150
+ --dry-run preview without writing
151
+ --json machine-readable output, no report text
114
152
  Remove a canonical skill (the next sync auto-removes the
115
153
  now-stale symlink on every managed agent)
116
154
  --dry-run preview the plan, write nothing
@@ -132,6 +170,20 @@ Commands:
132
170
  round-trip byte-for-byte back through memory sync.
133
171
  --dry-run preview the plan, write nothing
134
172
  --json machine-readable output, no report text
173
+ manage list
174
+ Show the canonical managed-agent write boundary.
175
+ manage set <ids|none>
176
+ manage add <ids>
177
+ manage remove <ids>
178
+ Explicitly replace, extend, or narrow the managed set. Removing
179
+ an agent preserves its existing native state; future Trellis
180
+ writes stop reaching it. Mutations are backup/rollback-enabled.
181
+ --dry-run preview current -> desired, write nothing
182
+ --json machine-readable output
183
+ kimi [args...]
184
+ Launch Kimi Code. When kimi-code Runtime delivery is \`mcp\`,
185
+ starts Kimi with an empty --skills-dir so Skills come from
186
+ trellis-runtime instead of native discovery.
135
187
  secrets audit
136
188
  Scan each present agent's real MCP config for leaked
137
189
  credentials and unexpected env var names
@@ -148,12 +200,23 @@ Commands:
148
200
 
149
201
  See docs/roadmap.md for what's built vs. planned.`);
150
202
  }
203
+ function printVersion() {
204
+ console.log(TRELLIS_VERSION);
205
+ }
151
206
  async function main(argv) {
152
207
  const [command, ...rest] = argv;
153
208
  if (!command || command === "--help" || command === "-h") {
154
209
  printUsage();
155
210
  return;
156
211
  }
212
+ if (command === "--version" || command === "-v") {
213
+ printVersion();
214
+ return;
215
+ }
216
+ if (command === "help") {
217
+ printUsage();
218
+ return;
219
+ }
157
220
  if (!KNOWN_COMMANDS.includes(command)) {
158
221
  console.error(`Unknown command: ${command}\n`);
159
222
  printUsage();
@@ -165,7 +228,7 @@ async function main(argv) {
165
228
  // sync --help`) must never fall through to actually running the command
166
229
  // it was asking about (real incident: `--help` isn't a flag any branch
167
230
  // recognizes, so it silently ran a real, non-dry-run `mcp sync`).
168
- if (rest.includes("--help") || rest.includes("-h")) {
231
+ if (command !== "kimi" && (rest.includes("--help") || rest.includes("-h"))) {
169
232
  printUsage();
170
233
  return;
171
234
  }
@@ -182,6 +245,10 @@ async function main(argv) {
182
245
  const gatewayAgents = gatewayAgentsIndex >= 0 ? rest[gatewayAgentsIndex + 1] : undefined;
183
246
  const memoryIndex = rest.indexOf("--memory");
184
247
  const memory = memoryIndex >= 0 ? rest[memoryIndex + 1] : undefined;
248
+ const memoryMigrateIndex = rest.indexOf("--memory-migrate");
249
+ const memoryMigrate = memoryMigrateIndex >= 0 ? rest[memoryMigrateIndex + 1] : undefined;
250
+ const selectionIndex = rest.indexOf("--selection");
251
+ const selectionFile = selectionIndex >= 0 ? rest[selectionIndex + 1] : undefined;
185
252
  const { exitCode } = await runOnboard({
186
253
  agent,
187
254
  manage,
@@ -189,6 +256,8 @@ async function main(argv) {
189
256
  hubUrl,
190
257
  gatewayAgents,
191
258
  memory,
259
+ memoryMigrate,
260
+ selectionFile,
192
261
  dryRun: rest.includes("--dry-run"),
193
262
  json: rest.includes("--json"),
194
263
  });
@@ -217,14 +286,16 @@ async function main(argv) {
217
286
  // Spawned by an agent, never typed by a person: stdout is the MCP
218
287
  // protocol stream for the rest of this process's life, so nothing here
219
288
  // may print to it (trellis-mcp-gateway-hosting design.md D2).
220
- if (command === "mcp-gateway") {
289
+ if (command === "mcp-gateway" || command === "mcp-runtime") {
221
290
  const parsed = parseMcpGatewayArgs(rest);
222
291
  if ("error" in parsed) {
223
292
  console.error(parsed.error);
224
293
  process.exitCode = 1;
225
294
  return;
226
295
  }
227
- const { exitCode } = await runMcpGateway({ agentId: parsed.agentId });
296
+ const { exitCode } = command === "mcp-runtime"
297
+ ? await runMcpRuntime({ agentId: parsed.agentId })
298
+ : await runMcpGateway({ agentId: parsed.agentId });
228
299
  process.exitCode = exitCode;
229
300
  return;
230
301
  }
@@ -255,7 +326,19 @@ async function main(argv) {
255
326
  }
256
327
  if (subcommand === "add") {
257
328
  const [name] = mcpRest;
258
- process.exitCode = runMcpAdd(name, parseMcpAddArgs(mcpRest), { json, dryRun }).exitCode;
329
+ process.exitCode = (await runMcpAdd(name, parseMcpAddArgs(mcpRest), { json, dryRun })).exitCode;
330
+ return;
331
+ }
332
+ if (subcommand === "import") {
333
+ const [file] = mcpRest;
334
+ process.exitCode = (await runMcpImport(file, { json, dryRun })).exitCode;
335
+ return;
336
+ }
337
+ if (subcommand === "set") {
338
+ const [name] = mcpRest;
339
+ const authIndex = mcpRest.indexOf("--auth");
340
+ const auth = authIndex >= 0 ? mcpRest[authIndex + 1] : undefined;
341
+ process.exitCode = runMcpSetAuth(name, auth, { json, dryRun }).exitCode;
259
342
  return;
260
343
  }
261
344
  if (subcommand === "remove") {
@@ -265,7 +348,7 @@ async function main(argv) {
265
348
  process.exitCode = 1;
266
349
  return;
267
350
  }
268
- process.exitCode = runMcpRemove(name, { json, dryRun }).exitCode;
351
+ process.exitCode = (await runMcpRemove(name, { json, dryRun })).exitCode;
269
352
  return;
270
353
  }
271
354
  if (subcommand === "auth") {
@@ -279,7 +362,7 @@ async function main(argv) {
279
362
  process.exitCode = exitCode;
280
363
  return;
281
364
  }
282
- console.error(`Unknown mcp subcommand: ${subcommand ?? "(none)"}\nUsage: trellis mcp sync|list|add <name>|remove <name>|auth <name>\n`);
365
+ console.error(`Unknown mcp subcommand: ${subcommand ?? "(none)"}\nUsage: trellis mcp sync|list|add <name>|set <name>|remove <name>|auth <name>\n`);
283
366
  process.exitCode = 1;
284
367
  return;
285
368
  }
@@ -300,7 +383,7 @@ async function main(argv) {
300
383
  process.exitCode = 1;
301
384
  return;
302
385
  }
303
- process.exitCode = runSkillAdd(name, from, { json, dryRun }).exitCode;
386
+ process.exitCode = (await runSkillAdd(name, from, { json, dryRun })).exitCode;
304
387
  return;
305
388
  }
306
389
  if (subcommand === "remove") {
@@ -310,10 +393,14 @@ async function main(argv) {
310
393
  process.exitCode = 1;
311
394
  return;
312
395
  }
313
- process.exitCode = runSkillRemove(name, { json, dryRun }).exitCode;
396
+ process.exitCode = (await runSkillRemove(name, { json, dryRun })).exitCode;
397
+ return;
398
+ }
399
+ if (subcommand === "update-builtin") {
400
+ process.exitCode = runSkillUpdateBuiltin({ json, dryRun }).exitCode;
314
401
  return;
315
402
  }
316
- console.error(`Unknown skill subcommand: ${subcommand ?? "(none)"}\nUsage: trellis skill list|add <name> --from <path>|remove <name>\n`);
403
+ console.error(`Unknown skill subcommand: ${subcommand ?? "(none)"}\nUsage: trellis skill list|add <name> --from <path>|remove <name>|update-builtin\n`);
317
404
  process.exitCode = 1;
318
405
  return;
319
406
  }
@@ -321,6 +408,21 @@ async function main(argv) {
321
408
  const [subcommand, ...memoryRest] = rest;
322
409
  const json = memoryRest.includes("--json");
323
410
  const dryRun = memoryRest.includes("--dry-run");
411
+ if (subcommand === "list") {
412
+ const entries = collectMemoryList();
413
+ if (json) {
414
+ console.log(JSON.stringify(entries, null, 2));
415
+ }
416
+ else if (entries.length === 0) {
417
+ console.log("No memories in canonical source yet.");
418
+ }
419
+ else {
420
+ for (const { name, scope } of entries) {
421
+ console.log(`${name} — ${scope.length > 0 ? scope.join(", ") : "(no managed agent reaches it)"}`);
422
+ }
423
+ }
424
+ return;
425
+ }
324
426
  if (subcommand === "sync") {
325
427
  process.exitCode = runMemorySync({ json, dryRun }).exitCode;
326
428
  return;
@@ -329,10 +431,24 @@ async function main(argv) {
329
431
  process.exitCode = runMemoryExtraction({ json, dryRun }).exitCode;
330
432
  return;
331
433
  }
332
- console.error(`Unknown memory subcommand: ${subcommand ?? "(none)"}\nUsage: trellis memory sync|extract\n`);
434
+ console.error(`Unknown memory subcommand: ${subcommand ?? "(none)"}\nUsage: trellis memory list|sync|extract\n`);
333
435
  process.exitCode = 1;
334
436
  return;
335
437
  }
438
+ if (command === "manage") {
439
+ const parsed = parseManageArgs(rest);
440
+ if ("error" in parsed) {
441
+ console.error(`${parsed.error}\nUsage: trellis manage list|set <ids|none>|add <ids>|remove <ids> [--dry-run] [--json]\n`);
442
+ process.exitCode = 1;
443
+ return;
444
+ }
445
+ process.exitCode = runManage(parsed).exitCode;
446
+ return;
447
+ }
448
+ if (command === "kimi") {
449
+ process.exitCode = (await runKimi(rest)).exitCode;
450
+ return;
451
+ }
336
452
  if (command === "secrets") {
337
453
  const [subcommand] = rest;
338
454
  if (subcommand !== "audit") {
@@ -1,9 +1,10 @@
1
1
  /**
2
2
  * `trellis doctor` — read-only cross-agent scan. No `.trellis/` canonical
3
- * source required (docs/roadmap.md): this compares the four agents' own
3
+ * source required (docs/roadmap.md): this compares the five agents' own
4
4
  * current state against each other, the same manual process used
5
5
  * throughout docs/research.md's investigation, now formalized.
6
6
  */
7
+ import { loadCanonicalSource } from "../core/canonical.js";
7
8
  import type { AgentId, AgentSnapshot } from "../core/types.js";
8
9
  /**
9
10
  * Interim default until P1 wires this from `.trellis/mcp/servers.yaml`'s
@@ -13,7 +14,7 @@ import type { AgentId, AgentSnapshot } from "../core/types.js";
13
14
  * machine.
14
15
  */
15
16
  export declare const DEFAULT_KNOWN_HOST_INJECTED: readonly string[];
16
- export type FindingKind = "probe-failed" | "duplication" | "collision" | "drift" | "case-mismatch" | "parse-diagnostic" | "mcp-unreachable";
17
+ export type FindingKind = "probe-failed" | "duplication" | "collision" | "drift" | "case-mismatch" | "parse-diagnostic" | "runtime-drift" | "mcp-unreachable";
17
18
  export interface Finding {
18
19
  kind: FindingKind;
19
20
  /** Omitted for a finding that names more than one agent (drift). */
@@ -92,6 +93,10 @@ export declare function detectCrossAgentDrift(snapshots: AgentSnapshot[]): Findi
92
93
  export declare function detectCaseMismatches(snapshots: AgentSnapshot[]): Finding[];
93
94
  export declare function detectParseDiagnostics(snapshots: AgentSnapshot[]): Finding[];
94
95
  export declare function detectMcpUnreachable(snapshots: AgentSnapshot[]): Finding[];
96
+ /** Compares runtime entries against the same canonical MCP plan that sync
97
+ * uses. Only missing Trellis-owned runtime edges are reported; extra
98
+ * user-authored MCP entries remain outside doctor ownership. */
99
+ export declare function detectRuntimeDrift(snapshots: AgentSnapshot[], canonical: Pick<ReturnType<typeof loadCanonicalSource>, "mcp" | "managedAgents" | "secretsPolicy">): Finding[];
95
100
  /** Exported so `trellis onboard` can reuse it verbatim for its own final
96
101
  * stage (trellis-onboard-closed-loop) rather than a second copy of this
97
102
  * formatting. */
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * `trellis doctor` — read-only cross-agent scan. No `.trellis/` canonical
3
- * source required (docs/roadmap.md): this compares the four agents' own
3
+ * source required (docs/roadmap.md): this compares the five agents' own
4
4
  * current state against each other, the same manual process used
5
5
  * throughout docs/research.md's investigation, now formalized.
6
6
  */
@@ -9,7 +9,10 @@ import * as claudeCodeProbe from "../probes/claude-code.js";
9
9
  import * as codexProbe from "../probes/codex.js";
10
10
  import * as kiroProbe from "../probes/kiro.js";
11
11
  import * as piProbe from "../probes/pi.js";
12
+ import * as kimiCodeProbe from "../probes/kimi-code.js";
13
+ import * as zcodeProbe from "../probes/zcode.js";
12
14
  import { loadCanonicalSource } from "../core/canonical.js";
15
+ import { GATEWAY_ENTRY_NAME, RUNTIME_ENTRY_NAME, resolveMcpPlan } from "../adapters/mcpPlan.js";
13
16
  import { ALL_AGENTS } from "../core/types.js";
14
17
  /**
15
18
  * Interim default until P1 wires this from `.trellis/mcp/servers.yaml`'s
@@ -32,6 +35,7 @@ const EXIT_NONZERO_KINDS = new Set([
32
35
  "drift",
33
36
  "case-mismatch",
34
37
  "parse-diagnostic",
38
+ "runtime-drift",
35
39
  ]);
36
40
  /** Exported so tests can assert on this resolution directly, without
37
41
  * routing through real per-agent probes `runDoctor` also runs. */
@@ -72,6 +76,8 @@ export async function collectDoctorReport(homeDir = homedir(), knownHostInjected
72
76
  { agent: "codex", run: () => codexProbe.probe(homeDir, { probeMcp }) },
73
77
  { agent: "kiro", run: () => kiroProbe.probe(homeDir, { probeMcp }) },
74
78
  { agent: "pi", run: () => piProbe.probe(homeDir) },
79
+ { agent: "kimi-code", run: () => kimiCodeProbe.probe(homeDir, { probeMcp }) },
80
+ { agent: "zcode", run: () => zcodeProbe.probe(homeDir, { probeMcp }) },
75
81
  ];
76
82
  // One agent erroring must not blank the other three's results.
77
83
  const settled = await Promise.allSettled(probeList.map((p) => p.run()));
@@ -89,7 +95,15 @@ export async function collectDoctorReport(homeDir = homedir(), knownHostInjected
89
95
  });
90
96
  }
91
97
  });
92
- findings.push(...detectDuplication(snapshots), ...detectCollisions(snapshots, knownHostInjected), ...detectCrossAgentDrift(snapshots), ...detectCaseMismatches(snapshots), ...detectParseDiagnostics(snapshots), ...detectMcpUnreachable(snapshots));
98
+ let canonical;
99
+ try {
100
+ canonical = loadCanonicalSource(homeDir);
101
+ }
102
+ catch {
103
+ // Doctor remains useful as a standalone cross-agent scanner when
104
+ // canonical has not been initialized yet.
105
+ }
106
+ findings.push(...detectDuplication(snapshots), ...detectCollisions(snapshots, knownHostInjected), ...detectCrossAgentDrift(snapshots), ...detectCaseMismatches(snapshots), ...detectParseDiagnostics(snapshots), ...(canonical ? detectRuntimeDrift(snapshots, canonical) : []), ...detectMcpUnreachable(snapshots));
93
107
  return { snapshots, findings };
94
108
  }
95
109
  /**
@@ -233,6 +247,30 @@ export function detectMcpUnreachable(snapshots) {
233
247
  }
234
248
  return findings;
235
249
  }
250
+ /** Compares runtime entries against the same canonical MCP plan that sync
251
+ * uses. Only missing Trellis-owned runtime edges are reported; extra
252
+ * user-authored MCP entries remain outside doctor ownership. */
253
+ export function detectRuntimeDrift(snapshots, canonical) {
254
+ const findings = [];
255
+ for (const snap of snapshots) {
256
+ if (!snap.present || !canonical.managedAgents.includes(snap.agent) || snap.agent === "pi")
257
+ continue;
258
+ const expected = resolveMcpPlan(snap.agent, canonical.mcp, canonical.managedAgents, canonical.secretsPolicy).desired
259
+ .map((entry) => entry.name)
260
+ .filter((name) => name === RUNTIME_ENTRY_NAME || name === GATEWAY_ENTRY_NAME);
261
+ const actual = new Set(snap.mcpServers.map((server) => server.name));
262
+ for (const name of expected) {
263
+ if (!actual.has(name)) {
264
+ findings.push({
265
+ kind: "runtime-drift",
266
+ agent: snap.agent,
267
+ message: "canonical expects MCP runtime entry \"" + name + "\" for " + snap.agent + ", but it is missing from the agent static configuration",
268
+ });
269
+ }
270
+ }
271
+ }
272
+ return findings;
273
+ }
236
274
  /** Exported so `trellis onboard` can reuse it verbatim for its own final
237
275
  * stage (trellis-onboard-closed-loop) rather than a second copy of this
238
276
  * formatting. */
@@ -29,7 +29,7 @@ export interface InitReport {
29
29
  /** Exported so `migrate` can byte-compare canonical `agents.md` against
30
30
  * this exact string (design.md D3, trellis-cli-migrate) rather than
31
31
  * retyping an equivalent one that could silently drift from this. */
32
- export declare const AGENTS_MD_TEMPLATE = "# Shared instructions\n\nWrite what every agent should know here \u2014 communication preferences,\nproject conventions, anything you'd otherwise repeat per agent.\n\nAlready using Claude Code, Codex, Kiro, or pi? `trellis migrate --from\n<agent>` imports its real instructions and skills instead of starting\nfrom this placeholder.\n";
32
+ export declare const AGENTS_MD_TEMPLATE = "# Shared instructions\n\nWrite what every agent should know here \u2014 communication preferences,\nproject conventions, anything you'd otherwise repeat per agent.\n\nAlready using Claude Code, Codex, Kiro, pi, Kimi Code, or ZCode? `trellis migrate --from\n<agent>` imports its real instructions and skills instead of starting\nfrom this placeholder.\n";
33
33
  /**
34
34
  * Trellis never spawns an installer itself (global package installs are
35
35
  * exactly the kind of irreversible, system-wide action that needs the
@@ -38,7 +38,9 @@ export declare const AGENTS_MD_TEMPLATE = "# Shared instructions\n\nWrite what e
38
38
  * own current install docs, same discipline as everything else here.
39
39
  */
40
40
  export declare const INSTALL_HINTS: Record<AgentId, string>;
41
- export declare function collectInitReport(homeDir?: string): Promise<InitReport>;
41
+ export declare function collectInitReport(homeDir?: string, options?: {
42
+ write?: boolean;
43
+ }): Promise<InitReport>;
42
44
  export declare function runInit(opts?: RunInitOptions): Promise<{
43
45
  exitCode: number;
44
46
  }>;
@@ -15,6 +15,8 @@ import * as claudeCodeProbe from "../probes/claude-code.js";
15
15
  import * as codexProbe from "../probes/codex.js";
16
16
  import * as kiroProbe from "../probes/kiro.js";
17
17
  import * as piProbe from "../probes/pi.js";
18
+ import * as kimiCodeProbe from "../probes/kimi-code.js";
19
+ import * as zcodeProbe from "../probes/zcode.js";
18
20
  import { ALL_AGENTS } from "../core/types.js";
19
21
  /** Exported so `migrate` can byte-compare canonical `agents.md` against
20
22
  * this exact string (design.md D3, trellis-cli-migrate) rather than
@@ -24,7 +26,7 @@ export const AGENTS_MD_TEMPLATE = `# Shared instructions
24
26
  Write what every agent should know here — communication preferences,
25
27
  project conventions, anything you'd otherwise repeat per agent.
26
28
 
27
- Already using Claude Code, Codex, Kiro, or pi? \`trellis migrate --from
29
+ Already using Claude Code, Codex, Kiro, pi, Kimi Code, or ZCode? \`trellis migrate --from
28
30
  <agent>\` imports its real instructions and skills instead of starting
29
31
  from this placeholder.
30
32
  `;
@@ -93,32 +95,46 @@ export const INSTALL_HINTS = {
93
95
  codex: "npm install -g @openai/codex",
94
96
  kiro: "https://kiro.dev/downloads/",
95
97
  pi: "npm install -g @earendil-works/pi-coding-agent",
98
+ "kimi-code": "curl -fsSL https://code.kimi.com/kimi-code/install.sh | bash",
99
+ zcode: "https://zcode.z.ai/en/docs/install",
96
100
  };
97
- function ensureFile(path, template) {
101
+ function ensureFile(path, template, write = true) {
98
102
  if (existsSync(path)) {
99
103
  return { path, action: "already-present" };
100
104
  }
101
- writeFileSync(path, template);
105
+ if (write)
106
+ writeFileSync(path, template);
102
107
  return { path, action: "create" };
103
108
  }
104
- export async function collectInitReport(homeDir = homedir()) {
109
+ export async function collectInitReport(homeDir = homedir(), options = {}) {
110
+ const write = options.write !== false;
105
111
  const root = join(homeDir, ".trellis");
106
- mkdirSync(root, { recursive: true });
107
- mkdirSync(join(root, "mcp"), { recursive: true });
108
- mkdirSync(join(root, "skills"), { recursive: true });
109
- mkdirSync(join(root, "agents"), { recursive: true });
110
- mkdirSync(join(root, "memories"), { recursive: true });
112
+ if (write) {
113
+ mkdirSync(root, { recursive: true });
114
+ mkdirSync(join(root, "mcp"), { recursive: true });
115
+ mkdirSync(join(root, "skills"), { recursive: true });
116
+ mkdirSync(join(root, "agents"), { recursive: true });
117
+ mkdirSync(join(root, "memories"), { recursive: true });
118
+ }
111
119
  const files = [
112
- ensureFile(join(root, "agents.md"), AGENTS_MD_TEMPLATE),
113
- ensureFile(join(root, "mcp", "servers.yaml"), serversYamlTemplate()),
114
- ensureFile(join(root, "secrets.policy.yaml"), secretsPolicyYamlTemplate()),
115
- ensureFile(join(root, "managed.yaml"), managedYamlTemplate()),
120
+ ensureFile(join(root, "agents.md"), AGENTS_MD_TEMPLATE, write),
121
+ ensureFile(join(root, "mcp", "servers.yaml"), serversYamlTemplate(), write),
122
+ ensureFile(join(root, "secrets.policy.yaml"), secretsPolicyYamlTemplate(), write),
123
+ ensureFile(join(root, "managed.yaml"), managedYamlTemplate(), write),
116
124
  ];
125
+ const here = dirname(fileURLToPath(import.meta.url));
126
+ const builtinSkillPath = join(root, "skills", "trellis-runtime", "SKILL.md");
127
+ const builtinSkillTemplate = readFileSync(join(here, "..", "..", "schema", "builtin-skills", "trellis-runtime", "SKILL.md"), "utf8");
128
+ if (write)
129
+ mkdirSync(dirname(builtinSkillPath), { recursive: true });
130
+ files.push(ensureFile(builtinSkillPath, builtinSkillTemplate, write));
117
131
  const probes = [
118
132
  { agent: "claude-code", run: () => claudeCodeProbe.probe(homeDir) },
119
133
  { agent: "codex", run: () => codexProbe.probe(homeDir) },
120
134
  { agent: "kiro", run: () => kiroProbe.probe(homeDir) },
121
135
  { agent: "pi", run: () => piProbe.probe(homeDir) },
136
+ { agent: "kimi-code", run: () => kimiCodeProbe.probe(homeDir) },
137
+ { agent: "zcode", run: () => zcodeProbe.probe(homeDir) },
122
138
  ];
123
139
  const settled = await Promise.allSettled(probes.map((p) => p.run()));
124
140
  const agents = settled.map((result, index) => {
@@ -0,0 +1,16 @@
1
+ /** Runtime-first Kimi Code launcher.
2
+ *
3
+ * Kimi automatically discovers ~/.agents/skills. When canonical delivery is
4
+ * `mcp`, passing one empty --skills-dir is the only documented way to replace
5
+ * both user/project Skill roots for this launch and prevent duplicate native
6
+ * Skill delivery. Native/both modes invoke Kimi normally.
7
+ */
8
+ import { spawn as spawnProcess } from "node:child_process";
9
+ export interface RunKimiOptions {
10
+ homeDir?: string;
11
+ env?: NodeJS.ProcessEnv;
12
+ spawn?: typeof spawnProcess;
13
+ }
14
+ export declare function runKimi(args?: readonly string[], opts?: RunKimiOptions): Promise<{
15
+ exitCode: number;
16
+ }>;
@@ -0,0 +1,64 @@
1
+ /** Runtime-first Kimi Code launcher.
2
+ *
3
+ * Kimi automatically discovers ~/.agents/skills. When canonical delivery is
4
+ * `mcp`, passing one empty --skills-dir is the only documented way to replace
5
+ * both user/project Skill roots for this launch and prevent duplicate native
6
+ * Skill delivery. Native/both modes invoke Kimi normally.
7
+ */
8
+ import { execFileSync, spawn as spawnProcess } from "node:child_process";
9
+ import { existsSync, mkdtempSync, rmSync } from "node:fs";
10
+ import { homedir, tmpdir } from "node:os";
11
+ import { join } from "node:path";
12
+ import { capabilityDeliveryForAgent } from "../core/types.js";
13
+ import { loadCanonicalSource } from "../core/canonical.js";
14
+ function resolveKimiCommand(homeDir, env) {
15
+ const explicit = env.TRELLIS_KIMI_BIN;
16
+ if (explicit && existsSync(explicit))
17
+ return explicit;
18
+ const homeBinary = join(env.KIMI_CODE_HOME ?? join(homeDir, ".kimi-code"), "bin", "kimi");
19
+ if (existsSync(homeBinary))
20
+ return homeBinary;
21
+ try {
22
+ return execFileSync("which", ["kimi"], { encoding: "utf8", env }).trim() || "kimi";
23
+ }
24
+ catch {
25
+ return "kimi";
26
+ }
27
+ }
28
+ function hasSkillsDirArg(args) {
29
+ return args.some((arg) => arg === "--skills-dir" || arg.startsWith("--skills-dir="));
30
+ }
31
+ export async function runKimi(args = [], opts = {}) {
32
+ const homeDir = opts.homeDir ?? homedir();
33
+ const env = { ...process.env, ...(opts.env ?? {}) };
34
+ let canonical;
35
+ try {
36
+ canonical = loadCanonicalSource(homeDir);
37
+ }
38
+ catch (err) {
39
+ console.error(err instanceof Error ? err.message : String(err));
40
+ return { exitCode: 1 };
41
+ }
42
+ const delivery = capabilityDeliveryForAgent("kimi-code", canonical.mcp);
43
+ const runtimeOnly = delivery === "mcp";
44
+ if (runtimeOnly && hasSkillsDirArg(args)) {
45
+ console.error("trellis kimi: --skills-dir cannot be combined with Runtime-only delivery; change mcp.runtime.delivery.kimi-code or use native Kimi directly");
46
+ return { exitCode: 1 };
47
+ }
48
+ let emptySkillsDir;
49
+ const launchArgs = [...args];
50
+ if (runtimeOnly) {
51
+ emptySkillsDir = mkdtempSync(join(tmpdir(), "trellis-kimi-empty-skills-"));
52
+ launchArgs.unshift("--skills-dir", emptySkillsDir);
53
+ }
54
+ const command = resolveKimiCommand(homeDir, env);
55
+ const spawn = opts.spawn ?? spawnProcess;
56
+ const child = spawn(command, launchArgs, { stdio: "inherit", env });
57
+ const exitCode = await new Promise((resolve) => {
58
+ child.once("error", () => resolve(1));
59
+ child.once("exit", (code, signal) => resolve(code ?? (signal ? 1 : 0)));
60
+ });
61
+ if (emptySkillsDir)
62
+ rmSync(emptySkillsDir, { recursive: true, force: true });
63
+ return { exitCode };
64
+ }