@kya-os/cli 1.7.0 → 1.8.3

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 (390) hide show
  1. package/dist/commands/agent.d.ts +35 -0
  2. package/dist/commands/agent.d.ts.map +1 -0
  3. package/dist/commands/agent.js +321 -0
  4. package/dist/commands/agent.js.map +1 -0
  5. package/dist/commands/build.js +2 -2
  6. package/dist/commands/build.js.map +1 -1
  7. package/dist/commands/check.js +3 -3
  8. package/dist/commands/check.js.map +1 -1
  9. package/dist/commands/checkpoint-init.d.ts +32 -0
  10. package/dist/commands/checkpoint-init.d.ts.map +1 -0
  11. package/dist/commands/checkpoint-init.js +521 -0
  12. package/dist/commands/checkpoint-init.js.map +1 -0
  13. package/dist/commands/claim.js +2 -2
  14. package/dist/commands/claim.js.map +1 -1
  15. package/dist/commands/dco.d.ts +59 -0
  16. package/dist/commands/dco.d.ts.map +1 -1
  17. package/dist/commands/dco.js +280 -5
  18. package/dist/commands/dco.js.map +1 -1
  19. package/dist/commands/dev.js +1 -1
  20. package/dist/commands/dev.js.map +1 -1
  21. package/dist/commands/doctor.d.ts.map +1 -1
  22. package/dist/commands/doctor.js +18 -24
  23. package/dist/commands/doctor.js.map +1 -1
  24. package/dist/commands/env.js +6 -6
  25. package/dist/commands/env.js.map +1 -1
  26. package/dist/commands/identity.js +3 -3
  27. package/dist/commands/identity.js.map +1 -1
  28. package/dist/commands/init-stages.d.ts +141 -0
  29. package/dist/commands/init-stages.d.ts.map +1 -0
  30. package/dist/commands/init-stages.js +684 -0
  31. package/dist/commands/init-stages.js.map +1 -0
  32. package/dist/commands/init.d.ts +46 -16
  33. package/dist/commands/init.d.ts.map +1 -1
  34. package/dist/commands/init.js +229 -279
  35. package/dist/commands/init.js.map +1 -1
  36. package/dist/commands/orchestrator.d.ts +18 -0
  37. package/dist/commands/orchestrator.d.ts.map +1 -0
  38. package/dist/commands/orchestrator.js +251 -0
  39. package/dist/commands/orchestrator.js.map +1 -0
  40. package/dist/commands/register.d.ts +1 -1
  41. package/dist/commands/register.d.ts.map +1 -1
  42. package/dist/commands/register.js +35 -7
  43. package/dist/commands/register.js.map +1 -1
  44. package/dist/commands/review.d.ts +48 -0
  45. package/dist/commands/review.d.ts.map +1 -0
  46. package/dist/commands/review.js +220 -0
  47. package/dist/commands/review.js.map +1 -0
  48. package/dist/commands/rotate.js +4 -4
  49. package/dist/commands/rotate.js.map +1 -1
  50. package/dist/commands/score.d.ts +15 -0
  51. package/dist/commands/score.d.ts.map +1 -0
  52. package/dist/commands/score.js +471 -0
  53. package/dist/commands/score.js.map +1 -0
  54. package/dist/commands/start.js +3 -3
  55. package/dist/commands/start.js.map +1 -1
  56. package/dist/commands/status.js +1 -1
  57. package/dist/commands/status.js.map +1 -1
  58. package/dist/commands/verify.js +6 -6
  59. package/dist/commands/verify.js.map +1 -1
  60. package/dist/dco.d.ts +4 -0
  61. package/dist/dco.d.ts.map +1 -0
  62. package/dist/dco.js +23 -0
  63. package/dist/dco.js.map +1 -0
  64. package/dist/index.js +62 -11
  65. package/dist/orchestrator/daemon.d.ts +137 -0
  66. package/dist/orchestrator/daemon.d.ts.map +1 -0
  67. package/dist/orchestrator/daemon.js +242 -0
  68. package/dist/orchestrator/daemon.js.map +1 -0
  69. package/dist/orchestrator/db/dispatches.d.ts +108 -0
  70. package/dist/orchestrator/db/dispatches.d.ts.map +1 -0
  71. package/dist/orchestrator/db/dispatches.js +122 -0
  72. package/dist/orchestrator/db/dispatches.js.map +1 -0
  73. package/dist/orchestrator/db/index.d.ts +50 -0
  74. package/dist/orchestrator/db/index.d.ts.map +1 -0
  75. package/dist/orchestrator/db/index.js +116 -0
  76. package/dist/orchestrator/db/index.js.map +1 -0
  77. package/dist/orchestrator/db/journal.d.ts +93 -0
  78. package/dist/orchestrator/db/journal.d.ts.map +1 -0
  79. package/dist/orchestrator/db/journal.js +91 -0
  80. package/dist/orchestrator/db/journal.js.map +1 -0
  81. package/dist/orchestrator/db/liveness.d.ts +97 -0
  82. package/dist/orchestrator/db/liveness.d.ts.map +1 -0
  83. package/dist/orchestrator/db/liveness.js +105 -0
  84. package/dist/orchestrator/db/liveness.js.map +1 -0
  85. package/dist/orchestrator/db/mission.d.ts +78 -0
  86. package/dist/orchestrator/db/mission.d.ts.map +1 -0
  87. package/dist/orchestrator/db/mission.js +99 -0
  88. package/dist/orchestrator/db/mission.js.map +1 -0
  89. package/dist/orchestrator/db/schema.d.ts +14 -0
  90. package/dist/orchestrator/db/schema.d.ts.map +1 -0
  91. package/dist/orchestrator/db/schema.js +169 -0
  92. package/dist/orchestrator/db/schema.js.map +1 -0
  93. package/dist/orchestrator/db/tickets.d.ts +147 -0
  94. package/dist/orchestrator/db/tickets.d.ts.map +1 -0
  95. package/dist/orchestrator/db/tickets.js +238 -0
  96. package/dist/orchestrator/db/tickets.js.map +1 -0
  97. package/dist/orchestrator/db/verdicts.d.ts +187 -0
  98. package/dist/orchestrator/db/verdicts.d.ts.map +1 -0
  99. package/dist/orchestrator/db/verdicts.js +197 -0
  100. package/dist/orchestrator/db/verdicts.js.map +1 -0
  101. package/dist/orchestrator/events.d.ts +69 -0
  102. package/dist/orchestrator/events.d.ts.map +1 -0
  103. package/dist/orchestrator/events.js +20 -0
  104. package/dist/orchestrator/events.js.map +1 -0
  105. package/dist/orchestrator/github-credential-anchor-sender.d.ts +159 -0
  106. package/dist/orchestrator/github-credential-anchor-sender.d.ts.map +1 -0
  107. package/dist/orchestrator/github-credential-anchor-sender.js +313 -0
  108. package/dist/orchestrator/github-credential-anchor-sender.js.map +1 -0
  109. package/dist/orchestrator/hub-dispatch.d.ts +120 -0
  110. package/dist/orchestrator/hub-dispatch.d.ts.map +1 -0
  111. package/dist/orchestrator/hub-dispatch.js +257 -0
  112. package/dist/orchestrator/hub-dispatch.js.map +1 -0
  113. package/dist/orchestrator/hub-observer.d.ts +201 -0
  114. package/dist/orchestrator/hub-observer.d.ts.map +1 -0
  115. package/dist/orchestrator/hub-observer.js +474 -0
  116. package/dist/orchestrator/hub-observer.js.map +1 -0
  117. package/dist/orchestrator/journal-writer.d.ts +80 -0
  118. package/dist/orchestrator/journal-writer.d.ts.map +1 -0
  119. package/dist/orchestrator/journal-writer.js +113 -0
  120. package/dist/orchestrator/journal-writer.js.map +1 -0
  121. package/dist/orchestrator/mcp/server.d.ts +136 -0
  122. package/dist/orchestrator/mcp/server.d.ts.map +1 -0
  123. package/dist/orchestrator/mcp/server.js +582 -0
  124. package/dist/orchestrator/mcp/server.js.map +1 -0
  125. package/dist/orchestrator/mcp/stdio.d.ts +22 -0
  126. package/dist/orchestrator/mcp/stdio.d.ts.map +1 -0
  127. package/dist/orchestrator/mcp/stdio.js +51 -0
  128. package/dist/orchestrator/mcp/stdio.js.map +1 -0
  129. package/dist/orchestrator/review.d.ts +131 -0
  130. package/dist/orchestrator/review.d.ts.map +1 -0
  131. package/dist/orchestrator/review.js +322 -0
  132. package/dist/orchestrator/review.js.map +1 -0
  133. package/dist/tui/app.d.ts +33 -0
  134. package/dist/tui/app.d.ts.map +1 -0
  135. package/dist/tui/app.js +71 -0
  136. package/dist/tui/app.js.map +1 -0
  137. package/dist/tui/components.d.ts +110 -0
  138. package/dist/tui/components.d.ts.map +1 -0
  139. package/dist/tui/components.js +118 -0
  140. package/dist/tui/components.js.map +1 -0
  141. package/dist/tui/index.d.ts +30 -0
  142. package/dist/tui/index.d.ts.map +1 -0
  143. package/dist/tui/index.js +95 -0
  144. package/dist/tui/index.js.map +1 -0
  145. package/dist/tui/keymap.d.ts +33 -0
  146. package/dist/tui/keymap.d.ts.map +1 -0
  147. package/dist/tui/keymap.js +49 -0
  148. package/dist/tui/keymap.js.map +1 -0
  149. package/dist/tui/nav.d.ts +29 -0
  150. package/dist/tui/nav.d.ts.map +1 -0
  151. package/dist/tui/nav.js +39 -0
  152. package/dist/tui/nav.js.map +1 -0
  153. package/dist/tui/sanitize.d.ts +25 -0
  154. package/dist/tui/sanitize.d.ts.map +1 -0
  155. package/dist/tui/sanitize.js +36 -0
  156. package/dist/tui/sanitize.js.map +1 -0
  157. package/dist/tui/theme.d.ts +32 -0
  158. package/dist/tui/theme.d.ts.map +1 -0
  159. package/dist/tui/theme.js +63 -0
  160. package/dist/tui/theme.js.map +1 -0
  161. package/dist/tui/views/agents.d.ts +67 -0
  162. package/dist/tui/views/agents.d.ts.map +1 -0
  163. package/dist/tui/views/agents.js +231 -0
  164. package/dist/tui/views/agents.js.map +1 -0
  165. package/dist/tui/views/index.d.ts +93 -0
  166. package/dist/tui/views/index.d.ts.map +1 -0
  167. package/dist/tui/views/index.js +150 -0
  168. package/dist/tui/views/index.js.map +1 -0
  169. package/dist/tui/views/registry.d.ts +22 -0
  170. package/dist/tui/views/registry.d.ts.map +1 -0
  171. package/dist/tui/views/registry.js +110 -0
  172. package/dist/tui/views/registry.js.map +1 -0
  173. package/dist/utils/agent/backoff.d.ts +31 -0
  174. package/dist/utils/agent/backoff.d.ts.map +1 -0
  175. package/dist/utils/agent/backoff.js +51 -0
  176. package/dist/utils/agent/backoff.js.map +1 -0
  177. package/dist/utils/agent/markers.d.ts +87 -0
  178. package/dist/utils/agent/markers.d.ts.map +1 -0
  179. package/dist/utils/agent/markers.js +147 -0
  180. package/dist/utils/agent/markers.js.map +1 -0
  181. package/dist/utils/agent/review.d.ts +67 -0
  182. package/dist/utils/agent/review.d.ts.map +1 -0
  183. package/dist/utils/agent/review.js +305 -0
  184. package/dist/utils/agent/review.js.map +1 -0
  185. package/dist/utils/agent/spawn-agent.d.ts +117 -0
  186. package/dist/utils/agent/spawn-agent.d.ts.map +1 -0
  187. package/dist/utils/agent/spawn-agent.js +177 -0
  188. package/dist/utils/agent/spawn-agent.js.map +1 -0
  189. package/dist/utils/agent/task.d.ts +101 -0
  190. package/dist/utils/agent/task.d.ts.map +1 -0
  191. package/dist/utils/agent/task.js +357 -0
  192. package/dist/utils/agent/task.js.map +1 -0
  193. package/dist/utils/agent/verify.d.ts +47 -0
  194. package/dist/utils/agent/verify.d.ts.map +1 -0
  195. package/dist/utils/agent/verify.js +144 -0
  196. package/dist/utils/agent/verify.js.map +1 -0
  197. package/dist/utils/agent-detector.d.ts +48 -0
  198. package/dist/utils/agent-detector.d.ts.map +1 -0
  199. package/dist/utils/agent-detector.js +74 -0
  200. package/dist/utils/agent-detector.js.map +1 -0
  201. package/dist/utils/agent-profile-stage.d.ts +70 -0
  202. package/dist/utils/agent-profile-stage.d.ts.map +1 -0
  203. package/dist/utils/agent-profile-stage.js +153 -0
  204. package/dist/utils/agent-profile-stage.js.map +1 -0
  205. package/dist/utils/agent-profiles.d.ts +27 -0
  206. package/dist/utils/agent-profiles.d.ts.map +1 -0
  207. package/dist/utils/agent-profiles.js +61 -0
  208. package/dist/utils/agent-profiles.js.map +1 -0
  209. package/dist/utils/checkpoint-api.d.ts +86 -0
  210. package/dist/utils/checkpoint-api.d.ts.map +1 -0
  211. package/dist/utils/checkpoint-api.js +196 -0
  212. package/dist/utils/checkpoint-api.js.map +1 -0
  213. package/dist/utils/checkpoint-env.d.ts +23 -0
  214. package/dist/utils/checkpoint-env.d.ts.map +1 -0
  215. package/dist/utils/checkpoint-env.js +59 -0
  216. package/dist/utils/checkpoint-env.js.map +1 -0
  217. package/dist/utils/checkpoint-scaffold.d.ts +61 -0
  218. package/dist/utils/checkpoint-scaffold.d.ts.map +1 -0
  219. package/dist/utils/checkpoint-scaffold.js +268 -0
  220. package/dist/utils/checkpoint-scaffold.js.map +1 -0
  221. package/dist/utils/cli-kit/browser.d.ts +24 -0
  222. package/dist/utils/cli-kit/browser.d.ts.map +1 -0
  223. package/dist/utils/cli-kit/browser.js +58 -0
  224. package/dist/utils/cli-kit/browser.js.map +1 -0
  225. package/dist/utils/cli-kit/claim-polling.d.ts +18 -0
  226. package/dist/utils/cli-kit/claim-polling.d.ts.map +1 -0
  227. package/dist/utils/{claim-polling.js → cli-kit/claim-polling.js} +19 -26
  228. package/dist/utils/cli-kit/claim-polling.js.map +1 -0
  229. package/dist/utils/cli-kit/diagnostics.d.ts +9 -0
  230. package/dist/utils/cli-kit/diagnostics.d.ts.map +1 -0
  231. package/dist/utils/cli-kit/diagnostics.js +11 -0
  232. package/dist/utils/cli-kit/diagnostics.js.map +1 -0
  233. package/dist/utils/cli-kit/fs-safe.d.ts +14 -0
  234. package/dist/utils/cli-kit/fs-safe.d.ts.map +1 -0
  235. package/dist/utils/cli-kit/fs-safe.js +20 -0
  236. package/dist/utils/cli-kit/fs-safe.js.map +1 -0
  237. package/dist/utils/cli-kit/index.d.ts +15 -0
  238. package/dist/utils/cli-kit/index.d.ts.map +1 -0
  239. package/dist/utils/cli-kit/index.js +10 -0
  240. package/dist/utils/cli-kit/index.js.map +1 -0
  241. package/dist/utils/cli-kit/json-file.d.ts +21 -0
  242. package/dist/utils/cli-kit/json-file.d.ts.map +1 -0
  243. package/dist/utils/cli-kit/json-file.js +51 -0
  244. package/dist/utils/cli-kit/json-file.js.map +1 -0
  245. package/dist/utils/cli-kit/marker-block.d.ts +26 -0
  246. package/dist/utils/cli-kit/marker-block.d.ts.map +1 -0
  247. package/dist/utils/cli-kit/marker-block.js +61 -0
  248. package/dist/utils/cli-kit/marker-block.js.map +1 -0
  249. package/dist/utils/cli-kit/paths.d.ts +15 -0
  250. package/dist/utils/cli-kit/paths.d.ts.map +1 -0
  251. package/dist/utils/cli-kit/paths.js +21 -0
  252. package/dist/utils/cli-kit/paths.js.map +1 -0
  253. package/dist/utils/cli-kit/secure-storage.d.ts +14 -0
  254. package/dist/utils/cli-kit/secure-storage.d.ts.map +1 -0
  255. package/dist/utils/cli-kit/secure-storage.js +20 -0
  256. package/dist/utils/cli-kit/secure-storage.js.map +1 -0
  257. package/dist/utils/cli-kit/step-report.d.ts +16 -0
  258. package/dist/utils/cli-kit/step-report.d.ts.map +1 -0
  259. package/dist/utils/cli-kit/step-report.js +36 -0
  260. package/dist/utils/cli-kit/step-report.js.map +1 -0
  261. package/dist/utils/dco/agent-metadata.d.ts +1 -1
  262. package/dist/utils/dco/agent-metadata.js +1 -1
  263. package/dist/utils/dco/agent-metadata.js.map +1 -1
  264. package/dist/utils/dco/claude-config.d.ts +18 -8
  265. package/dist/utils/dco/claude-config.d.ts.map +1 -1
  266. package/dist/utils/dco/claude-config.js +33 -79
  267. package/dist/utils/dco/claude-config.js.map +1 -1
  268. package/dist/utils/dco/dispatch.d.ts +134 -0
  269. package/dist/utils/dco/dispatch.d.ts.map +1 -0
  270. package/dist/utils/dco/dispatch.js +399 -0
  271. package/dist/utils/dco/dispatch.js.map +1 -0
  272. package/dist/utils/dco/fix.d.ts +122 -0
  273. package/dist/utils/dco/fix.d.ts.map +1 -0
  274. package/dist/utils/dco/fix.js +560 -0
  275. package/dist/utils/dco/fix.js.map +1 -0
  276. package/dist/utils/dco/git-config.d.ts.map +1 -1
  277. package/dist/utils/dco/git-config.js +5 -3
  278. package/dist/utils/dco/git-config.js.map +1 -1
  279. package/dist/utils/dco/github.d.ts +101 -0
  280. package/dist/utils/dco/github.d.ts.map +1 -1
  281. package/dist/utils/dco/github.js +133 -0
  282. package/dist/utils/dco/github.js.map +1 -1
  283. package/dist/utils/dco/paths.d.ts +1 -8
  284. package/dist/utils/dco/paths.d.ts.map +1 -1
  285. package/dist/utils/dco/paths.js +3 -12
  286. package/dist/utils/dco/paths.js.map +1 -1
  287. package/dist/utils/dco/render.d.ts +1 -1
  288. package/dist/utils/dco/render.d.ts.map +1 -1
  289. package/dist/utils/dco/render.js +4 -21
  290. package/dist/utils/dco/render.js.map +1 -1
  291. package/dist/utils/dco/resolve-agent.d.ts +54 -0
  292. package/dist/utils/dco/resolve-agent.d.ts.map +1 -0
  293. package/dist/utils/dco/resolve-agent.js +164 -0
  294. package/dist/utils/dco/resolve-agent.js.map +1 -0
  295. package/dist/utils/dco/setup.d.ts +10 -7
  296. package/dist/utils/dco/setup.d.ts.map +1 -1
  297. package/dist/utils/dco/setup.js +264 -199
  298. package/dist/utils/dco/setup.js.map +1 -1
  299. package/dist/utils/dco/signing-key-writer.d.ts +40 -0
  300. package/dist/utils/dco/signing-key-writer.d.ts.map +1 -0
  301. package/dist/utils/dco/signing-key-writer.js +76 -0
  302. package/dist/utils/dco/signing-key-writer.js.map +1 -0
  303. package/dist/utils/dco/ssh-key.d.ts +50 -0
  304. package/dist/utils/dco/ssh-key.d.ts.map +1 -1
  305. package/dist/utils/dco/ssh-key.js +129 -8
  306. package/dist/utils/dco/ssh-key.js.map +1 -1
  307. package/dist/utils/dco/status.d.ts +1 -1
  308. package/dist/utils/dco/status.d.ts.map +1 -1
  309. package/dist/utils/dco/status.js +3 -3
  310. package/dist/utils/dco/status.js.map +1 -1
  311. package/dist/utils/dco/verify.d.ts +170 -0
  312. package/dist/utils/dco/verify.d.ts.map +1 -0
  313. package/dist/utils/dco/verify.js +550 -0
  314. package/dist/utils/dco/verify.js.map +1 -0
  315. package/dist/utils/dependency-installer.d.ts +37 -0
  316. package/dist/utils/dependency-installer.d.ts.map +1 -0
  317. package/dist/utils/dependency-installer.js +32 -0
  318. package/dist/utils/dependency-installer.js.map +1 -0
  319. package/dist/utils/github-credential-stage.d.ts +87 -0
  320. package/dist/utils/github-credential-stage.d.ts.map +1 -0
  321. package/dist/utils/github-credential-stage.js +168 -0
  322. package/dist/utils/github-credential-stage.js.map +1 -0
  323. package/dist/utils/github-credential.d.ts +160 -0
  324. package/dist/utils/github-credential.d.ts.map +1 -0
  325. package/dist/utils/github-credential.js +308 -0
  326. package/dist/utils/github-credential.js.map +1 -0
  327. package/dist/utils/gitignore.d.ts +17 -0
  328. package/dist/utils/gitignore.d.ts.map +1 -0
  329. package/dist/utils/gitignore.js +40 -0
  330. package/dist/utils/gitignore.js.map +1 -0
  331. package/dist/utils/hub-config.d.ts +21 -0
  332. package/dist/utils/hub-config.d.ts.map +1 -0
  333. package/dist/utils/hub-config.js +28 -0
  334. package/dist/utils/hub-config.js.map +1 -0
  335. package/dist/utils/identity-heal.d.ts +16 -0
  336. package/dist/utils/identity-heal.d.ts.map +1 -0
  337. package/dist/utils/identity-heal.js +37 -0
  338. package/dist/utils/identity-heal.js.map +1 -0
  339. package/dist/utils/init/pipeline.d.ts +74 -0
  340. package/dist/utils/init/pipeline.d.ts.map +1 -0
  341. package/dist/utils/init/pipeline.js +96 -0
  342. package/dist/utils/init/pipeline.js.map +1 -0
  343. package/dist/utils/poll.d.ts +64 -0
  344. package/dist/utils/poll.d.ts.map +1 -0
  345. package/dist/utils/poll.js +76 -0
  346. package/dist/utils/poll.js.map +1 -0
  347. package/dist/utils/register-agent-identity.d.ts +67 -0
  348. package/dist/utils/register-agent-identity.d.ts.map +1 -0
  349. package/dist/utils/register-agent-identity.js +34 -0
  350. package/dist/utils/register-agent-identity.js.map +1 -0
  351. package/dist/utils/review/did-web-key.d.ts +34 -0
  352. package/dist/utils/review/did-web-key.d.ts.map +1 -0
  353. package/dist/utils/review/did-web-key.js +104 -0
  354. package/dist/utils/review/did-web-key.js.map +1 -0
  355. package/dist/utils/review/load-registry.d.ts +33 -0
  356. package/dist/utils/review/load-registry.d.ts.map +1 -0
  357. package/dist/utils/review/load-registry.js +62 -0
  358. package/dist/utils/review/load-registry.js.map +1 -0
  359. package/dist/utils/review/verdict-verify.d.ts +43 -0
  360. package/dist/utils/review/verdict-verify.d.ts.map +1 -0
  361. package/dist/utils/review/verdict-verify.js +53 -0
  362. package/dist/utils/review/verdict-verify.js.map +1 -0
  363. package/dist/utils/review-registry-writer.d.ts +52 -0
  364. package/dist/utils/review-registry-writer.d.ts.map +1 -0
  365. package/dist/utils/review-registry-writer.js +79 -0
  366. package/dist/utils/review-registry-writer.js.map +1 -0
  367. package/dist/utils/should-install-dependency.d.ts +17 -0
  368. package/dist/utils/should-install-dependency.d.ts.map +1 -0
  369. package/dist/utils/should-install-dependency.js +25 -0
  370. package/dist/utils/should-install-dependency.js.map +1 -0
  371. package/dist/utils/tool-readiness.d.ts +57 -0
  372. package/dist/utils/tool-readiness.d.ts.map +1 -0
  373. package/dist/utils/tool-readiness.js +114 -0
  374. package/dist/utils/tool-readiness.js.map +1 -0
  375. package/dist/utils/which.d.ts +2 -0
  376. package/dist/utils/which.d.ts.map +1 -0
  377. package/dist/utils/which.js +22 -0
  378. package/dist/utils/which.js.map +1 -0
  379. package/dist/version.d.ts +15 -0
  380. package/dist/version.d.ts.map +1 -0
  381. package/dist/version.js +29 -0
  382. package/dist/version.js.map +1 -0
  383. package/package.json +19 -6
  384. package/dist/utils/claim-polling.d.ts +0 -21
  385. package/dist/utils/claim-polling.d.ts.map +0 -1
  386. package/dist/utils/claim-polling.js.map +0 -1
  387. package/dist/utils/dco/fs-safe.d.ts +0 -14
  388. package/dist/utils/dco/fs-safe.d.ts.map +0 -1
  389. package/dist/utils/dco/fs-safe.js +0 -20
  390. package/dist/utils/dco/fs-safe.js.map +0 -1
@@ -1,11 +1,6 @@
1
+ import { type StepResult, type StepStatus } from "../cli-kit/index.js";
1
2
  import { type GitIdentity } from "./git-config.js";
2
- export type StepStatus = "done" | "skipped" | "failed" | "action-required" | "would-change";
3
- export interface StepResult {
4
- id: string;
5
- title: string;
6
- status: StepStatus;
7
- detail?: string;
8
- }
3
+ export type { StepStatus, StepResult };
9
4
  export interface DcoAgentInfo {
10
5
  did: string;
11
6
  name: string;
@@ -25,6 +20,14 @@ export interface DcoSetupOptions {
25
20
  force?: boolean;
26
21
  /** Allow interactive prompts (agent name fallback, scope refresh). */
27
22
  interactive?: boolean;
23
+ /**
24
+ * Wire signing for this EXISTING registered agent instead of resolving
25
+ * identity from this checkout's `.mcpi/`. Skips the identity.json preflight
26
+ * entirely and requires the key to already exist at `signingKeyPath(agent)`
27
+ * (never generated or converted in this mode). See `dco dispatch <slug>`,
28
+ * which derives the same did:web/url/email from the slug.
29
+ */
30
+ agent?: string;
28
31
  }
29
32
  export interface DcoSetupResult {
30
33
  ok: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../../src/utils/dco/setup.ts"],"names":[],"mappings":"AAmBA,OAAO,EAML,KAAK,WAAW,EACjB,MAAM,iBAAiB,CAAC;AAmBzB,MAAM,MAAM,UAAU,GAClB,MAAM,GACN,SAAS,GACT,QAAQ,GACR,iBAAiB,GACjB,cAAc,CAAC;AAEnB,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,oDAAoD;IACpD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gEAAgE;IAChE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,sEAAsE;IACtE,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,OAAO,CAAC;IACZ,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oFAAoF;IACpF,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AA2HD;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,cAAc,CAAC,CA8oBzB"}
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../../src/utils/dco/setup.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAOvE,OAAO,EAML,KAAK,WAAW,EACjB,MAAM,iBAAiB,CAAC;AAoBzB,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC;AAEvC,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,oDAAoD;IACpD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gEAAgE;IAChE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,sEAAsE;IACtE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,OAAO,CAAC;IACZ,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oFAAoF;IACpF,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAkKD;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,cAAc,CAAC,CAsqBzB"}
@@ -1,5 +1,5 @@
1
1
  import { execFile } from "child_process";
2
- import { chmodSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync, } from "fs";
2
+ import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "fs";
3
3
  import { tmpdir } from "os";
4
4
  import { join } from "path";
5
5
  import { promisify } from "util";
@@ -7,8 +7,9 @@ import { readAgentMetadata, writeAgentMetadata } from "./agent-metadata.js";
7
7
  import { buildAttributionBlock, updateClaudeSettings, upsertClaudeMdBlock, } from "./claude-config.js";
8
8
  import { detectSigningConflicts, getGitConfigValue, installTrailerHook, isGitRepo, setGitConfig, } from "./git-config.js";
9
9
  import { GhNotInstalledError, GhScopeError, getGhUser, githubNoreplyEmail, isGhAuthenticated, isGhInstalled, listSigningKeys, refreshAuthScope, signingKeyAlreadyUploaded, uploadSigningKey, SCOPE_REFRESH_COMMAND, } from "./github.js";
10
- import { isValidSlug, keysDir, signingKeyPath } from "./paths.js";
11
- import { convertEd25519ToSshKey } from "./ssh-key.js";
10
+ import { isValidSlug, signingKeyPath } from "./paths.js";
11
+ import { writeAgentSigningKey } from "./signing-key-writer.js";
12
+ import { sshFingerprintFromPublicKeyLine } from "./ssh-key.js";
12
13
  const execFileAsync = promisify(execFile);
13
14
  function slugify(value) {
14
15
  return value
@@ -23,11 +24,14 @@ function slugify(value) {
23
24
  */
24
25
  function sanitizeIdentityValue(value) {
25
26
  // eslint-disable-next-line no-control-regex
26
- return value.replace(/[\u0000-\u001f\u007f]+/g, " ").replace(/\s+/g, " ").trim();
27
+ return value
28
+ .replace(/[\u0000-\u001f\u007f]+/g, " ")
29
+ .replace(/\s+/g, " ")
30
+ .trim();
27
31
  }
28
32
  /**
29
33
  * Distinguishes a missing identity from a present-but-unparseable one. The
30
- * two need different advice: "run mcpi register" after a corrupt read would
34
+ * two need different advice: "run kya-os register" after a corrupt read would
31
35
  * overwrite a potentially recoverable key with a brand new identity.
32
36
  */
33
37
  function readIdentityFile(cwd) {
@@ -110,6 +114,35 @@ async function promptForAgentName() {
110
114
  ]);
111
115
  return { name: name.trim(), slug };
112
116
  }
117
+ /**
118
+ * Resolve the human committer's name/email: prefer git config, and only fall
119
+ * back to the authenticated GitHub profile for whichever field git is
120
+ * missing (never both at once, so a configured name survives a missing
121
+ * email or vice versa). Shared by both identity-resolution paths in
122
+ * `runDcoSetup`: this half of Step 2 is identical whether the agent side
123
+ * came from `.mcpi/` or from an explicit agent slug.
124
+ */
125
+ async function resolveHumanIdentity(cwd) {
126
+ const gitName = await getGitConfigValue("user.name", cwd);
127
+ const gitEmail = await getGitConfigValue("user.email", cwd);
128
+ let ghUser = null;
129
+ if ((!gitName || !gitEmail) &&
130
+ (await isGhInstalled()) &&
131
+ (await isGhAuthenticated())) {
132
+ ghUser = await getGhUser();
133
+ }
134
+ // Use || (not ??) so an explicitly-empty git value is treated as missing,
135
+ // consistent with the truthiness gate above that decides to fetch gh.
136
+ const resolvedName = gitName || (ghUser ? ghUser.name || ghUser.login : undefined);
137
+ const resolvedEmail = gitEmail || (ghUser ? githubNoreplyEmail(ghUser) : undefined);
138
+ if (!resolvedName || !resolvedEmail) {
139
+ throw new Error("Could not resolve your git identity. Set git config user.name and user.email, or authenticate gh.");
140
+ }
141
+ return {
142
+ name: sanitizeIdentityValue(resolvedName),
143
+ email: sanitizeIdentityValue(resolvedEmail),
144
+ };
145
+ }
113
146
  /**
114
147
  * Orchestrates the full DCO/attribution setup. Steps run in order; the three
115
148
  * foundation steps (preflight, identities, key material) abort the run when
@@ -160,217 +193,252 @@ export async function runDcoSetup(options = {}) {
160
193
  ...laterSteps,
161
194
  ]);
162
195
  }
163
- const identityRead = readIdentityFile(cwd);
164
- const identity = identityRead.status === "ok" ? identityRead.identity : null;
165
- let preflightFailure = null;
166
- if (identityRead.status === "corrupt") {
167
- preflightFailure =
168
- ".mcpi/identity.json exists but could not be parsed. Do NOT re-run `mcpi register` (it would overwrite the identity); inspect or restore the file first.";
169
- }
170
- else if (!identity?.privateKey || !identity?.did) {
171
- preflightFailure =
172
- identityRead.status === "ok"
173
- ? ".mcpi/identity.json is missing required fields (did, privateKey). Inspect or restore the file before continuing."
174
- : "No agent identity found in .mcpi/identity.json. Run `mcpi register` first, then re-run `mcpi dco setup`.";
175
- }
176
- else if (await isIdentityTrackedByGit(cwd)) {
177
- preflightFailure =
178
- ".mcpi/identity.json is tracked by git. A committed identity may have been shipped by the repo author; refusing to configure signing with it. Remove it from git history and generate your own identity with `mcpi register`.";
179
- }
180
- if (preflightFailure || !identity?.privateKey || !identity?.did) {
181
- steps.push({
182
- id: "preflight",
183
- title: "Preflight checks",
184
- status: "failed",
185
- detail: preflightFailure ??
186
- "No agent identity found in .mcpi/identity.json. Run `mcpi register` first, then re-run `mcpi dco setup`.",
187
- });
188
- return abort([
189
- { id: "identities", title: "Resolve agent and human identity" },
190
- { id: "key-material", title: "Write SSH signing key" },
191
- ...laterSteps,
192
- ]);
193
- }
194
- steps.push({ id: "preflight", title: "Preflight checks", status: "done" });
195
- // Step 2: resolve identities
196
+ // Steps 1-3 (preflight, identity resolution, key material) branch here and
197
+ // rejoin at Step 4: an explicit agent slug wires signing for an EXISTING
198
+ // registered agent and never reads, requires, or writes `.mcpi/` — the
199
+ // identity is derived from the slug alone (the same derivation
200
+ // `dco dispatch <slug>` uses) and the key must already exist on disk,
201
+ // never generated or converted here. `agent`/`human`/`keyMaterial`/
202
+ // `privateKeyPath`/`publicKeyPath` are populated by whichever branch runs;
203
+ // both either abort the whole run or leave all five set by the time
204
+ // Step 4 reads them.
196
205
  let agent;
197
206
  let human;
198
- try {
199
- const metadata = readAgentMetadata(cwd);
200
- if (metadata?.did && metadata.did !== identity.did) {
201
- throw new Error(`.mcpi/agent.json is for a different agent (${metadata.did}) than .mcpi/identity.json (${identity.did}). Fix or remove agent.json before continuing.`);
202
- }
203
- // Only trust agent.json for attribution when it is cryptographically bound
204
- // to this identity (its did matches identity.json). Unbound metadata (no
205
- // did, e.g. planted in an untrusted repo) is ignored so it cannot spoof the
206
- // agent name/slug/url; the resolved values are then persisted with the real
207
- // did, healing the binding for later runs.
208
- const boundMetadata = metadata && metadata.did === identity.did ? metadata : null;
209
- let name = boundMetadata?.name ?? process.env.AGENT_NAME;
210
- let slug = boundMetadata?.slug ?? process.env.AGENT_SLUG;
211
- if ((!name || !slug) && interactive && !options.dryRun) {
212
- const prompted = await promptForAgentName();
213
- name = name ?? prompted.name;
214
- slug = slug ?? prompted.slug;
215
- }
216
- if (!name || !slug) {
217
- throw new Error("Agent name/slug unknown. Run `mcpi register`, or set AGENT_NAME and AGENT_SLUG.");
218
- }
219
- // The interactive prompt validates its own input; values arriving from
220
- // agent.json or the environment must pass the same shape check because
221
- // the slug becomes a filename under the keys directory.
222
- if (!isValidSlug(slug)) {
223
- throw new Error(`Invalid agent slug "${slug}": must be lowercase letters, numbers, and dashes.`);
224
- }
225
- name = sanitizeIdentityValue(name);
226
- const metadataUrl = boundMetadata?.url
227
- ? sanitizeIdentityValue(boundMetadata.url)
228
- : undefined;
207
+ let keyMaterial;
208
+ let privateKeyPath;
209
+ let publicKeyPath;
210
+ if (options.agent) {
211
+ if (!isValidSlug(options.agent)) {
212
+ steps.push({
213
+ id: "preflight",
214
+ title: "Preflight checks",
215
+ status: "failed",
216
+ detail: `Invalid agent slug "${options.agent}": must be lowercase letters, numbers, and dashes.`,
217
+ });
218
+ return abort([
219
+ { id: "identities", title: "Resolve agent and human identity" },
220
+ { id: "key-material", title: "Write SSH signing key" },
221
+ ...laterSteps,
222
+ ]);
223
+ }
224
+ steps.push({ id: "preflight", title: "Preflight checks", status: "done" });
225
+ const slug = options.agent;
229
226
  agent = {
230
- did: identity.did,
231
- name,
227
+ did: `did:web:knowthat.ai:agents:${slug}`,
228
+ name: slug,
232
229
  slug,
233
- url: metadataUrl && isTrustedAgentUrl(metadataUrl)
234
- ? metadataUrl
235
- : `https://knowthat.ai/agents/${slug}`,
230
+ url: `https://knowthat.ai/agents/${slug}`,
236
231
  email: `${slug}@agents.knowthat.ai`,
237
232
  };
238
- // Resolve the human name and email INDEPENDENTLY, each preferring the
239
- // configured git value and only falling back to gh for the field that is
240
- // missing. Resolving them together would let a missing email drop a
241
- // configured name (or vice versa) in favor of the GitHub profile.
242
- // Reading gh here is unrelated to the key upload, so it stays available
243
- // even under --skip-github (which only suppresses the upload).
244
- const gitName = await getGitConfigValue("user.name", cwd);
245
- const gitEmail = await getGitConfigValue("user.email", cwd);
246
- let ghUser = null;
247
- if ((!gitName || !gitEmail) &&
248
- (await isGhInstalled()) &&
249
- (await isGhAuthenticated())) {
250
- ghUser = await getGhUser();
251
- }
252
- // Use || (not ??) so an explicitly-empty git value is treated as missing,
253
- // consistent with the truthiness gate above that decides to fetch gh.
254
- const resolvedName = gitName || (ghUser ? ghUser.name || ghUser.login : undefined);
255
- const resolvedEmail = gitEmail || (ghUser ? githubNoreplyEmail(ghUser) : undefined);
256
- if (!resolvedName || !resolvedEmail) {
257
- throw new Error("Could not resolve your git identity. Set git config user.name and user.email, or authenticate gh.");
258
- }
259
- human = {
260
- name: sanitizeIdentityValue(resolvedName),
261
- email: sanitizeIdentityValue(resolvedEmail),
262
- };
263
- result.agent = agent;
264
- result.human = human;
265
- // Persist resolved metadata when the bound record was incomplete (prompted,
266
- // from env, or unbound), so a later non-interactive run resolves the agent
267
- // without prompting AND the did binding is written for future runs.
268
- // Best-effort: a cache-write failure must not fail identity resolution.
269
- if (!options.dryRun &&
270
- (!boundMetadata?.name || !boundMetadata?.slug || !boundMetadata?.did)) {
271
- try {
272
- writeAgentMetadata(cwd, {
273
- name: agent.name,
274
- slug: agent.slug,
275
- url: agent.url,
276
- did: agent.did,
277
- });
278
- }
279
- catch (error) {
280
- result.metadataPersistWarning =
281
- error instanceof Error ? error.message : String(error);
282
- }
233
+ try {
234
+ human = await resolveHumanIdentity(cwd);
235
+ result.agent = agent;
236
+ result.human = human;
237
+ steps.push({
238
+ id: "identities",
239
+ title: "Resolve agent and human identity",
240
+ status: "done",
241
+ detail: `agent=${agent.name} (${agent.slug}), human=${human.name} <${human.email}>`,
242
+ });
283
243
  }
284
- steps.push({
285
- id: "identities",
286
- title: "Resolve agent and human identity",
287
- status: "done",
288
- detail: `agent=${agent.name} (${agent.slug}), human=${human.name} <${human.email}>`,
289
- });
290
- }
291
- catch (error) {
292
- steps.push({
293
- id: "identities",
294
- title: "Resolve agent and human identity",
295
- status: "failed",
296
- detail: error instanceof Error ? error.message : String(error),
297
- });
298
- return abort([
299
- { id: "key-material", title: "Write SSH signing key" },
300
- ...laterSteps,
301
- ]);
302
- }
303
- // Step 3: key material
304
- let keyMaterial;
305
- // Slug was validated in the identities step; signingKeyPath re-checks and
306
- // always yields a path inside the keys directory.
307
- const privateKeyPath = signingKeyPath(agent.slug);
308
- const publicKeyPath = `${privateKeyPath}.pub`;
309
- // Only the write branch below sets this; a failure before it (e.g. a bad
310
- // identity.json that fails conversion) must NOT delete pre-existing keys.
311
- let startedKeyWrite = false;
312
- try {
313
- keyMaterial = convertEd25519ToSshKey(identity.privateKey, `mcpi:${agent.slug}`, { expectedPublicKeyBase64: identity.publicKey });
314
- result.privateKeyPath = privateKeyPath;
315
- result.fingerprint = keyMaterial.fingerprint;
316
- // Compare BOTH files against the (now deterministic) expected material, so
317
- // a corrupt/truncated private key with an intact .pub is detected and
318
- // rewritten rather than left in place to fail signing forever.
319
- const privUpToDate = existsSync(privateKeyPath) &&
320
- readFileSync(privateKeyPath, "utf-8") === keyMaterial.privateKeyPem;
321
- const pubUpToDate = existsSync(publicKeyPath) &&
322
- readFileSync(publicKeyPath, "utf-8").trim() === keyMaterial.publicKeyLine;
323
- if (privUpToDate && pubUpToDate) {
244
+ catch (error) {
245
+ steps.push({
246
+ id: "identities",
247
+ title: "Resolve agent and human identity",
248
+ status: "failed",
249
+ detail: error instanceof Error ? error.message : String(error),
250
+ });
251
+ return abort([
252
+ { id: "key-material", title: "Write SSH signing key" },
253
+ ...laterSteps,
254
+ ]);
255
+ }
256
+ // Slug was validated above; signingKeyPath re-checks and always yields a
257
+ // path inside the keys directory.
258
+ privateKeyPath = signingKeyPath(agent.slug);
259
+ publicKeyPath = `${privateKeyPath}.pub`;
260
+ if (!existsSync(privateKeyPath) || !existsSync(publicKeyPath)) {
324
261
  steps.push({
325
262
  id: "key-material",
326
263
  title: "Write SSH signing key",
327
- status: "done",
328
- detail: `Already present at ${privateKeyPath}`,
264
+ status: "failed",
265
+ detail: `No key for agent "${agent.slug}" at ${privateKeyPath}; run setup in the repo that registered it, or check the slug.`,
329
266
  });
267
+ return abort(laterSteps);
330
268
  }
331
- else if (options.dryRun) {
269
+ try {
270
+ const publicKeyLine = readFileSync(publicKeyPath, "utf-8").trim();
271
+ const fingerprint = sshFingerprintFromPublicKeyLine(publicKeyLine);
272
+ keyMaterial = { publicKeyLine, fingerprint };
273
+ result.privateKeyPath = privateKeyPath;
274
+ result.fingerprint = fingerprint;
332
275
  steps.push({
333
276
  id: "key-material",
334
277
  title: "Write SSH signing key",
335
- status: "would-change",
336
- detail: `Would write ${privateKeyPath} and ${publicKeyPath}`,
278
+ status: "done",
279
+ detail: `Using existing key at ${privateKeyPath} (${fingerprint})`,
337
280
  });
338
281
  }
339
- else {
340
- mkdirSync(keysDir(), { recursive: true, mode: 0o700 });
341
- startedKeyWrite = true;
342
- // mode on write avoids any window where the key exists with loose
343
- // permissions; the chmod covers overwrites of a pre-existing file,
344
- // where the mode option is ignored.
345
- writeFileSync(privateKeyPath, keyMaterial.privateKeyPem, { mode: 0o600 });
346
- chmodSync(privateKeyPath, 0o600);
347
- writeFileSync(publicKeyPath, keyMaterial.publicKeyLine + "\n", {
348
- mode: 0o644,
349
- });
350
- chmodSync(publicKeyPath, 0o644);
282
+ catch (error) {
351
283
  steps.push({
352
284
  id: "key-material",
353
285
  title: "Write SSH signing key",
354
- status: "done",
355
- detail: `${privateKeyPath} (${keyMaterial.fingerprint})`,
286
+ status: "failed",
287
+ detail: error instanceof Error ? error.message : String(error),
356
288
  });
289
+ return abort(laterSteps);
357
290
  }
358
291
  }
359
- catch (error) {
360
- // Clean up only a key pair THIS run started writing (a half-written pair);
361
- // a failure before the write (e.g. bad identity.json) must leave any
362
- // pre-existing valid keys intact so signing is not silently broken.
363
- if (!options.dryRun && startedKeyWrite) {
364
- rmSync(privateKeyPath, { force: true });
365
- rmSync(publicKeyPath, { force: true });
292
+ else {
293
+ const identityRead = readIdentityFile(cwd);
294
+ const identity = identityRead.status === "ok" ? identityRead.identity : null;
295
+ let preflightFailure = null;
296
+ if (identityRead.status === "corrupt") {
297
+ preflightFailure =
298
+ ".mcpi/identity.json exists but could not be parsed. Do NOT re-run `kya-os register` (it would overwrite the identity); inspect or restore the file first.";
299
+ }
300
+ else if (!identity?.privateKey || !identity?.did) {
301
+ preflightFailure =
302
+ identityRead.status === "ok"
303
+ ? ".mcpi/identity.json is missing required fields (did, privateKey). Inspect or restore the file before continuing."
304
+ : "No agent identity found in .mcpi/identity.json. Run `kya-os register` first, then re-run `dco setup`.";
305
+ }
306
+ else if (await isIdentityTrackedByGit(cwd)) {
307
+ preflightFailure =
308
+ ".mcpi/identity.json is tracked by git. A committed identity may have been shipped by the repo author; refusing to configure signing with it. Remove it from git history and generate your own identity with `kya-os register`.";
309
+ }
310
+ if (preflightFailure || !identity?.privateKey || !identity?.did) {
311
+ steps.push({
312
+ id: "preflight",
313
+ title: "Preflight checks",
314
+ status: "failed",
315
+ detail: preflightFailure ??
316
+ "No agent identity found in .mcpi/identity.json. Run `kya-os register` first, then re-run `dco setup`.",
317
+ });
318
+ return abort([
319
+ { id: "identities", title: "Resolve agent and human identity" },
320
+ { id: "key-material", title: "Write SSH signing key" },
321
+ ...laterSteps,
322
+ ]);
366
323
  }
324
+ steps.push({ id: "preflight", title: "Preflight checks", status: "done" });
325
+ try {
326
+ const metadata = readAgentMetadata(cwd);
327
+ if (metadata?.did && metadata.did !== identity.did) {
328
+ throw new Error(`.mcpi/agent.json is for a different agent (${metadata.did}) than .mcpi/identity.json (${identity.did}). Fix or remove agent.json before continuing.`);
329
+ }
330
+ // Only trust agent.json for attribution when it is cryptographically bound
331
+ // to this identity (its did matches identity.json). Unbound metadata (no
332
+ // did, e.g. planted in an untrusted repo) is ignored so it cannot spoof the
333
+ // agent name/slug/url; the resolved values are then persisted with the real
334
+ // did, healing the binding for later runs.
335
+ const boundMetadata = metadata && metadata.did === identity.did ? metadata : null;
336
+ let name = boundMetadata?.name ?? process.env.AGENT_NAME;
337
+ let slug = boundMetadata?.slug ?? process.env.AGENT_SLUG;
338
+ if ((!name || !slug) && interactive && !options.dryRun) {
339
+ const prompted = await promptForAgentName();
340
+ name = name ?? prompted.name;
341
+ slug = slug ?? prompted.slug;
342
+ }
343
+ if (!name || !slug) {
344
+ throw new Error("Agent name/slug unknown. Run `kya-os register`, or set AGENT_NAME and AGENT_SLUG.");
345
+ }
346
+ // The interactive prompt validates its own input; values arriving from
347
+ // agent.json or the environment must pass the same shape check because
348
+ // the slug becomes a filename under the keys directory.
349
+ if (!isValidSlug(slug)) {
350
+ throw new Error(`Invalid agent slug "${slug}": must be lowercase letters, numbers, and dashes.`);
351
+ }
352
+ name = sanitizeIdentityValue(name);
353
+ const metadataUrl = boundMetadata?.url
354
+ ? sanitizeIdentityValue(boundMetadata.url)
355
+ : undefined;
356
+ agent = {
357
+ did: identity.did,
358
+ name,
359
+ slug,
360
+ url: metadataUrl && isTrustedAgentUrl(metadataUrl)
361
+ ? metadataUrl
362
+ : `https://knowthat.ai/agents/${slug}`,
363
+ email: `${slug}@agents.knowthat.ai`,
364
+ };
365
+ // Resolve the human name and email INDEPENDENTLY, each preferring the
366
+ // configured git value and only falling back to gh for the field that is
367
+ // missing. Resolving them together would let a missing email drop a
368
+ // configured name (or vice versa) in favor of the GitHub profile.
369
+ // Reading gh here is unrelated to the key upload, so it stays available
370
+ // even under --skip-github (which only suppresses the upload).
371
+ human = await resolveHumanIdentity(cwd);
372
+ result.agent = agent;
373
+ result.human = human;
374
+ // Persist resolved metadata when the bound record was incomplete (prompted,
375
+ // from env, or unbound), so a later non-interactive run resolves the agent
376
+ // without prompting AND the did binding is written for future runs.
377
+ // Best-effort: a cache-write failure must not fail identity resolution.
378
+ if (!options.dryRun &&
379
+ (!boundMetadata?.name || !boundMetadata?.slug || !boundMetadata?.did)) {
380
+ try {
381
+ writeAgentMetadata(cwd, {
382
+ name: agent.name,
383
+ slug: agent.slug,
384
+ url: agent.url,
385
+ did: agent.did,
386
+ });
387
+ }
388
+ catch (error) {
389
+ result.metadataPersistWarning =
390
+ error instanceof Error ? error.message : String(error);
391
+ }
392
+ }
393
+ steps.push({
394
+ id: "identities",
395
+ title: "Resolve agent and human identity",
396
+ status: "done",
397
+ detail: `agent=${agent.name} (${agent.slug}), human=${human.name} <${human.email}>`,
398
+ });
399
+ }
400
+ catch (error) {
401
+ steps.push({
402
+ id: "identities",
403
+ title: "Resolve agent and human identity",
404
+ status: "failed",
405
+ detail: error instanceof Error ? error.message : String(error),
406
+ });
407
+ return abort([
408
+ { id: "key-material", title: "Write SSH signing key" },
409
+ ...laterSteps,
410
+ ]);
411
+ }
412
+ // Slug was validated in the identities step. The conversion, idempotency,
413
+ // and cleanup-on-failure logic live in writeAgentSigningKey, shared with
414
+ // kya-os init's agent-profile stage so both write through the exact same
415
+ // path.
416
+ const keyResult = writeAgentSigningKey(agent.slug,
417
+ // Narrowed property access (not the bare `identity` object) so TS sees
418
+ // these as `string`, matching the preflight check above.
419
+ { privateKey: identity.privateKey, publicKey: identity.publicKey }, { dryRun: options.dryRun });
420
+ privateKeyPath = keyResult.privateKeyPath;
421
+ if (keyResult.status === "failed") {
422
+ steps.push({
423
+ id: "key-material",
424
+ title: "Write SSH signing key",
425
+ status: "failed",
426
+ detail: keyResult.detail,
427
+ });
428
+ return abort(laterSteps);
429
+ }
430
+ keyMaterial = {
431
+ fingerprint: keyResult.fingerprint,
432
+ publicKeyLine: keyResult.publicKeyLine,
433
+ };
434
+ result.privateKeyPath = privateKeyPath;
435
+ result.fingerprint = keyResult.fingerprint;
367
436
  steps.push({
368
437
  id: "key-material",
369
438
  title: "Write SSH signing key",
370
- status: "failed",
371
- detail: error instanceof Error ? error.message : String(error),
439
+ status: keyResult.status,
440
+ detail: keyResult.detail,
372
441
  });
373
- return abort(laterSteps);
374
442
  }
375
443
  // Step 4: GitHub upload
376
444
  if (options.skipGithub) {
@@ -388,7 +456,7 @@ export async function runDcoSetup(options = {}) {
388
456
  id: "github-upload",
389
457
  title: "Upload signing key to GitHub",
390
458
  status: "action-required",
391
- detail: "GitHub CLI not found. Install from https://cli.github.com, run `gh auth login`, then re-run `mcpi dco setup`.",
459
+ detail: "GitHub CLI not found. Install from https://cli.github.com, run `gh auth login`, then re-run `dco setup`.",
392
460
  });
393
461
  }
394
462
  else if (!(await isGhAuthenticated())) {
@@ -396,7 +464,7 @@ export async function runDcoSetup(options = {}) {
396
464
  id: "github-upload",
397
465
  title: "Upload signing key to GitHub",
398
466
  status: "action-required",
399
- detail: "Not authenticated. Run `gh auth login`, then re-run `mcpi dco setup`.",
467
+ detail: "Not authenticated. Run `gh auth login`, then re-run `dco setup`.",
400
468
  });
401
469
  }
402
470
  else {
@@ -438,7 +506,7 @@ export async function runDcoSetup(options = {}) {
438
506
  id: "github-upload",
439
507
  title: "Upload signing key to GitHub",
440
508
  status: "action-required",
441
- detail: "Upload declined. Re-run `mcpi dco setup` when you are ready to upload the key.",
509
+ detail: "Upload declined. Re-run `dco setup` when you are ready to upload the key.",
442
510
  });
443
511
  }
444
512
  else {
@@ -458,7 +526,7 @@ export async function runDcoSetup(options = {}) {
458
526
  id: "github-upload",
459
527
  title: "Upload signing key to GitHub",
460
528
  status: "action-required",
461
- detail: `${error.message} Then re-run \`mcpi dco setup\`.`,
529
+ detail: `${error.message} Then re-run \`dco setup\`.`,
462
530
  });
463
531
  }
464
532
  else if (error instanceof GhNotInstalledError) {
@@ -626,12 +694,7 @@ export async function runDcoSetup(options = {}) {
626
694
  else {
627
695
  try {
628
696
  const block = buildAttributionBlock({
629
- agentName: agent.name,
630
- agentUrl: agent.url,
631
697
  includeTrailerInstructions: hookFallback,
632
- humanName: human.name,
633
- humanEmail: human.email,
634
- agentEmail: agent.email,
635
698
  });
636
699
  const md = upsertClaudeMdBlock(cwd, block, { dryRun: options.dryRun });
637
700
  const settings = updateClaudeSettings(cwd, { dryRun: options.dryRun });
@@ -680,7 +743,9 @@ export async function runDcoSetup(options = {}) {
680
743
  "Trailer instructions would be added to the CLAUDE.md attribution block instead.";
681
744
  }
682
745
  else {
683
- outcome = `Trailers were NOT added to CLAUDE.md (${options.skipClaude ? "--skip-claude" : "the Claude Code step did not complete"}); add Signed-off-by / Co-authored-by manually or re-run without --skip-claude.`;
746
+ outcome = `Trailers were NOT added to CLAUDE.md (${options.skipClaude
747
+ ? "--skip-claude"
748
+ : "the Claude Code step did not complete"}); add Signed-off-by / Co-authored-by manually or re-run without --skip-claude.`;
684
749
  }
685
750
  if (trailerStep) {
686
751
  trailerStep.detail = `${hookFallbackDetail} ${outcome}`;
@@ -701,7 +766,7 @@ export async function runDcoSetup(options = {}) {
701
766
  const verifyDir = mkdtempSync(join(tmpdir(), "mcpi-dco-verify-"));
702
767
  const payloadPath = join(verifyDir, "payload");
703
768
  try {
704
- writeFileSync(payloadPath, "mcpi dco verification payload\n");
769
+ writeFileSync(payloadPath, "dco verification payload\n");
705
770
  await execFileAsync("ssh-keygen", [
706
771
  "-Y",
707
772
  "sign",