@dharta/cli 0.6.77 → 0.6.78

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 (293) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +215 -11
  3. package/dist/agent.js +3 -2
  4. package/dist/agent.js.map +1 -1
  5. package/dist/api-error.js +6 -6
  6. package/dist/api-error.js.map +1 -1
  7. package/dist/cli.d.ts +3 -0
  8. package/dist/cli.js +860 -149
  9. package/dist/cli.js.map +1 -1
  10. package/dist/command-tree.d.ts +3 -0
  11. package/dist/command-tree.js +10 -0
  12. package/dist/command-tree.js.map +1 -0
  13. package/dist/commands/agents.d.ts +54 -17
  14. package/dist/commands/agents.js +246 -136
  15. package/dist/commands/agents.js.map +1 -1
  16. package/dist/commands/analytics.js +6 -5
  17. package/dist/commands/analytics.js.map +1 -1
  18. package/dist/commands/api.js +71 -86
  19. package/dist/commands/api.js.map +1 -1
  20. package/dist/commands/appearance.js +5 -6
  21. package/dist/commands/appearance.js.map +1 -1
  22. package/dist/commands/artifact.js +7 -6
  23. package/dist/commands/artifact.js.map +1 -1
  24. package/dist/commands/audit-log.js +2 -1
  25. package/dist/commands/audit-log.js.map +1 -1
  26. package/dist/commands/auth.js +26 -6
  27. package/dist/commands/auth.js.map +1 -1
  28. package/dist/commands/caps.js +11 -15
  29. package/dist/commands/caps.js.map +1 -1
  30. package/dist/commands/deploy.js +25 -10
  31. package/dist/commands/deploy.js.map +1 -1
  32. package/dist/commands/dev.d.ts +10 -1
  33. package/dist/commands/dev.js +56 -25
  34. package/dist/commands/dev.js.map +1 -1
  35. package/dist/commands/doctor.d.ts +2 -0
  36. package/dist/commands/doctor.js +60 -0
  37. package/dist/commands/doctor.js.map +1 -1
  38. package/dist/commands/embed-keys.js +4 -13
  39. package/dist/commands/embed-keys.js.map +1 -1
  40. package/dist/commands/env.js +4 -7
  41. package/dist/commands/env.js.map +1 -1
  42. package/dist/commands/files.js +3 -4
  43. package/dist/commands/files.js.map +1 -1
  44. package/dist/commands/fleet.d.ts +129 -0
  45. package/dist/commands/fleet.js +408 -0
  46. package/dist/commands/fleet.js.map +1 -0
  47. package/dist/commands/genui.d.ts +2 -0
  48. package/dist/commands/genui.js +53 -0
  49. package/dist/commands/genui.js.map +1 -0
  50. package/dist/commands/git-credential.js +2 -3
  51. package/dist/commands/git-credential.js.map +1 -1
  52. package/dist/commands/kartas.d.ts +9 -0
  53. package/dist/commands/kartas.js +33 -11
  54. package/dist/commands/kartas.js.map +1 -1
  55. package/dist/commands/keys.d.ts +17 -18
  56. package/dist/commands/keys.js +108 -19
  57. package/dist/commands/keys.js.map +1 -1
  58. package/dist/commands/login.js +2 -1
  59. package/dist/commands/login.js.map +1 -1
  60. package/dist/commands/members.d.ts +10 -0
  61. package/dist/commands/members.js +20 -6
  62. package/dist/commands/members.js.map +1 -1
  63. package/dist/commands/model-connections.d.ts +44 -0
  64. package/dist/commands/model-connections.js +435 -0
  65. package/dist/commands/model-connections.js.map +1 -0
  66. package/dist/commands/open.d.ts +2 -2
  67. package/dist/commands/open.js +4 -3
  68. package/dist/commands/open.js.map +1 -1
  69. package/dist/commands/org.d.ts +9 -0
  70. package/dist/commands/org.js +42 -0
  71. package/dist/commands/org.js.map +1 -0
  72. package/dist/commands/organization.d.ts +16 -0
  73. package/dist/commands/organization.js +118 -0
  74. package/dist/commands/organization.js.map +1 -0
  75. package/dist/commands/parity.js +1 -3
  76. package/dist/commands/parity.js.map +1 -1
  77. package/dist/commands/repos.d.ts +4 -0
  78. package/dist/commands/repos.js +17 -0
  79. package/dist/commands/repos.js.map +1 -0
  80. package/dist/commands/rollback.js +2 -3
  81. package/dist/commands/rollback.js.map +1 -1
  82. package/dist/commands/schedules.js +26 -21
  83. package/dist/commands/schedules.js.map +1 -1
  84. package/dist/commands/scopes.js +8 -1
  85. package/dist/commands/scopes.js.map +1 -1
  86. package/dist/commands/sessions.js +9 -3
  87. package/dist/commands/sessions.js.map +1 -1
  88. package/dist/commands/setup.js +5 -4
  89. package/dist/commands/setup.js.map +1 -1
  90. package/dist/commands/update.d.ts +1 -0
  91. package/dist/commands/update.js +24 -11
  92. package/dist/commands/update.js.map +1 -1
  93. package/dist/commands/webhooks.d.ts +4 -1
  94. package/dist/commands/webhooks.js +21 -16
  95. package/dist/commands/webhooks.js.map +1 -1
  96. package/dist/completions.js +24 -13
  97. package/dist/completions.js.map +1 -1
  98. package/dist/config.d.ts +12 -0
  99. package/dist/config.js +121 -7
  100. package/dist/config.js.map +1 -1
  101. package/dist/context.d.ts +2 -0
  102. package/dist/context.js +23 -7
  103. package/dist/context.js.map +1 -1
  104. package/dist/docs/cli-reference.d.ts +2 -0
  105. package/dist/docs/cli-reference.js +191 -0
  106. package/dist/docs/cli-reference.js.map +1 -0
  107. package/dist/exit-codes.d.ts +25 -0
  108. package/dist/exit-codes.js +107 -0
  109. package/dist/exit-codes.js.map +1 -0
  110. package/dist/genui.d.ts +178 -0
  111. package/dist/genui.js +1130 -0
  112. package/dist/genui.js.map +1 -0
  113. package/dist/harnesses.js +2 -1
  114. package/dist/harnesses.js.map +1 -1
  115. package/dist/jq.d.ts +4 -0
  116. package/dist/jq.js +91 -0
  117. package/dist/jq.js.map +1 -0
  118. package/dist/login-offer.js +6 -2
  119. package/dist/login-offer.js.map +1 -1
  120. package/dist/manifest.d.ts +12 -0
  121. package/dist/manifest.js +126 -0
  122. package/dist/manifest.js.map +1 -1
  123. package/dist/model-auth.d.ts +29 -0
  124. package/dist/model-auth.js +117 -0
  125. package/dist/model-auth.js.map +1 -0
  126. package/dist/model-settings.d.ts +23 -0
  127. package/dist/model-settings.js +186 -0
  128. package/dist/model-settings.js.map +1 -0
  129. package/dist/money.js +2 -1
  130. package/dist/money.js.map +1 -1
  131. package/dist/output.d.ts +6 -0
  132. package/dist/output.js +54 -0
  133. package/dist/output.js.map +1 -1
  134. package/dist/runtime.d.ts +1 -1
  135. package/dist/runtime.js +1 -1
  136. package/dist/scaffold.js +2 -1
  137. package/dist/scaffold.js.map +1 -1
  138. package/dist/validators.js +17 -11
  139. package/dist/validators.js.map +1 -1
  140. package/dist/version-check.d.ts +1 -1
  141. package/dist/version-check.js +1 -1
  142. package/dist/version-check.js.map +1 -1
  143. package/node_modules/@dharta/contracts/LICENSE +21 -0
  144. package/node_modules/@dharta/contracts/README.md +45 -0
  145. package/node_modules/@dharta/contracts/artifact-runtime.json +750 -0
  146. package/node_modules/@dharta/contracts/dist/activity.d.ts +62 -0
  147. package/node_modules/@dharta/contracts/dist/activity.d.ts.map +1 -0
  148. package/node_modules/@dharta/contracts/dist/activity.js +178 -0
  149. package/node_modules/@dharta/contracts/dist/activity.js.map +1 -0
  150. package/node_modules/@dharta/contracts/dist/artifact-runtime-formats.d.ts +20 -0
  151. package/node_modules/@dharta/contracts/dist/artifact-runtime-formats.d.ts.map +1 -0
  152. package/node_modules/@dharta/contracts/dist/artifact-runtime-formats.js +53 -0
  153. package/node_modules/@dharta/contracts/dist/artifact-runtime-formats.js.map +1 -0
  154. package/node_modules/@dharta/contracts/dist/artifact-runtime-validators.generated.d.ts +37 -0
  155. package/node_modules/@dharta/contracts/dist/artifact-runtime-validators.generated.d.ts.map +1 -0
  156. package/node_modules/@dharta/contracts/dist/artifact-runtime-validators.generated.js +5107 -0
  157. package/node_modules/@dharta/contracts/dist/artifact-runtime-validators.generated.js.map +1 -0
  158. package/node_modules/@dharta/contracts/dist/artifact-runtime.d.ts +154 -0
  159. package/node_modules/@dharta/contracts/dist/artifact-runtime.d.ts.map +1 -0
  160. package/node_modules/@dharta/contracts/dist/artifact-runtime.generated.d.ts +1670 -0
  161. package/node_modules/@dharta/contracts/dist/artifact-runtime.generated.d.ts.map +1 -0
  162. package/node_modules/@dharta/contracts/dist/artifact-runtime.generated.js +1903 -0
  163. package/node_modules/@dharta/contracts/dist/artifact-runtime.generated.js.map +1 -0
  164. package/node_modules/@dharta/contracts/dist/artifact-runtime.js +377 -0
  165. package/node_modules/@dharta/contracts/dist/artifact-runtime.js.map +1 -0
  166. package/node_modules/@dharta/contracts/dist/index.d.ts +6 -0
  167. package/node_modules/@dharta/contracts/dist/index.d.ts.map +1 -0
  168. package/node_modules/@dharta/contracts/dist/index.js +6 -0
  169. package/node_modules/@dharta/contracts/dist/index.js.map +1 -0
  170. package/node_modules/@dharta/contracts/dist/model-auth.d.ts +31 -0
  171. package/node_modules/@dharta/contracts/dist/model-auth.d.ts.map +1 -0
  172. package/node_modules/@dharta/contracts/dist/model-auth.js +45 -0
  173. package/node_modules/@dharta/contracts/dist/model-auth.js.map +1 -0
  174. package/node_modules/@dharta/contracts/dist/tasks.d.ts +44 -0
  175. package/node_modules/@dharta/contracts/dist/tasks.d.ts.map +1 -0
  176. package/node_modules/@dharta/contracts/dist/tasks.js +127 -0
  177. package/node_modules/@dharta/contracts/dist/tasks.js.map +1 -0
  178. package/node_modules/@dharta/contracts/dist/wire-events.d.ts +71 -0
  179. package/node_modules/@dharta/contracts/dist/wire-events.d.ts.map +1 -0
  180. package/node_modules/@dharta/contracts/dist/wire-events.js +48 -0
  181. package/node_modules/@dharta/contracts/dist/wire-events.js.map +1 -0
  182. package/node_modules/@dharta/contracts/model-auth-capabilities-v1.json +168 -0
  183. package/node_modules/@dharta/contracts/model-auth-reasons-v1.json +38 -0
  184. package/node_modules/@dharta/contracts/package.json +44 -0
  185. package/node_modules/@dharta/contracts/src/activity.ts +215 -0
  186. package/node_modules/@dharta/contracts/src/artifact-runtime-formats.ts +54 -0
  187. package/node_modules/@dharta/contracts/src/artifact-runtime-validators.generated.ts +29 -0
  188. package/node_modules/@dharta/contracts/src/artifact-runtime.generated.ts +2093 -0
  189. package/node_modules/@dharta/contracts/src/artifact-runtime.ts +520 -0
  190. package/node_modules/@dharta/contracts/src/index.ts +5 -0
  191. package/node_modules/@dharta/contracts/src/model-auth.ts +82 -0
  192. package/node_modules/@dharta/contracts/src/tasks.ts +142 -0
  193. package/node_modules/@dharta/contracts/src/wire-events.ts +150 -0
  194. package/node_modules/@dharta/contracts/wire-events.json +29 -0
  195. package/node_modules/@dharta/sdk/LICENSE +1 -1
  196. package/node_modules/@dharta/sdk/README.md +22 -8
  197. package/node_modules/@dharta/sdk/dist/errors.d.ts +9 -7
  198. package/node_modules/@dharta/sdk/dist/errors.d.ts.map +1 -1
  199. package/node_modules/@dharta/sdk/dist/errors.js +36 -18
  200. package/node_modules/@dharta/sdk/dist/errors.js.map +1 -1
  201. package/node_modules/@dharta/sdk/dist/fleet.d.ts +69 -0
  202. package/node_modules/@dharta/sdk/dist/fleet.d.ts.map +1 -0
  203. package/node_modules/@dharta/sdk/dist/fleet.js +240 -0
  204. package/node_modules/@dharta/sdk/dist/fleet.js.map +1 -0
  205. package/node_modules/@dharta/sdk/dist/http.d.ts +6 -2
  206. package/node_modules/@dharta/sdk/dist/http.d.ts.map +1 -1
  207. package/node_modules/@dharta/sdk/dist/http.js +71 -12
  208. package/node_modules/@dharta/sdk/dist/http.js.map +1 -1
  209. package/node_modules/@dharta/sdk/dist/idempotency.d.ts +12 -0
  210. package/node_modules/@dharta/sdk/dist/idempotency.d.ts.map +1 -0
  211. package/node_modules/@dharta/sdk/dist/idempotency.js +72 -0
  212. package/node_modules/@dharta/sdk/dist/idempotency.js.map +1 -0
  213. package/node_modules/@dharta/sdk/dist/index.d.ts +20 -6
  214. package/node_modules/@dharta/sdk/dist/index.d.ts.map +1 -1
  215. package/node_modules/@dharta/sdk/dist/index.js +27 -4
  216. package/node_modules/@dharta/sdk/dist/index.js.map +1 -1
  217. package/node_modules/@dharta/sdk/dist/resources.d.ts +108 -13
  218. package/node_modules/@dharta/sdk/dist/resources.d.ts.map +1 -1
  219. package/node_modules/@dharta/sdk/dist/resources.js +403 -57
  220. package/node_modules/@dharta/sdk/dist/resources.js.map +1 -1
  221. package/node_modules/@dharta/sdk/dist/types.d.ts +436 -16
  222. package/node_modules/@dharta/sdk/dist/types.d.ts.map +1 -1
  223. package/node_modules/@dharta/sdk/dist/types.js +31 -2
  224. package/node_modules/@dharta/sdk/dist/types.js.map +1 -1
  225. package/node_modules/@dharta/sdk/package.json +9 -3
  226. package/node_modules/@dharta/sdk/src/errors.ts +41 -18
  227. package/node_modules/@dharta/sdk/src/fleet.ts +339 -0
  228. package/node_modules/@dharta/sdk/src/http.ts +110 -17
  229. package/node_modules/@dharta/sdk/src/idempotency.ts +101 -0
  230. package/node_modules/@dharta/sdk/src/index.ts +50 -11
  231. package/node_modules/@dharta/sdk/src/resources.ts +549 -68
  232. package/node_modules/@dharta/sdk/src/types.ts +629 -20
  233. package/package.json +16 -6
  234. package/src/agent.ts +3 -2
  235. package/src/api-error.ts +6 -5
  236. package/src/cli.ts +978 -163
  237. package/src/command-tree.ts +13 -0
  238. package/src/commands/agents.ts +365 -167
  239. package/src/commands/analytics.ts +6 -5
  240. package/src/commands/api.ts +73 -92
  241. package/src/commands/appearance.ts +5 -6
  242. package/src/commands/artifact.ts +7 -6
  243. package/src/commands/audit-log.ts +2 -1
  244. package/src/commands/auth.ts +25 -5
  245. package/src/commands/caps.ts +11 -15
  246. package/src/commands/deploy.ts +18 -4
  247. package/src/commands/dev.ts +86 -25
  248. package/src/commands/doctor.ts +69 -0
  249. package/src/commands/embed-keys.ts +4 -14
  250. package/src/commands/env.ts +4 -7
  251. package/src/commands/files.ts +3 -4
  252. package/src/commands/fleet.ts +672 -0
  253. package/src/commands/genui.ts +59 -0
  254. package/src/commands/git-credential.ts +2 -3
  255. package/src/commands/kartas.ts +45 -11
  256. package/src/commands/keys.ts +152 -35
  257. package/src/commands/login.ts +2 -1
  258. package/src/commands/members.ts +31 -6
  259. package/src/commands/model-connections.ts +547 -0
  260. package/src/commands/open.ts +5 -4
  261. package/src/commands/org.ts +57 -0
  262. package/src/commands/organization.ts +153 -0
  263. package/src/commands/parity.ts +1 -3
  264. package/src/commands/repos.ts +23 -0
  265. package/src/commands/rollback.ts +2 -3
  266. package/src/commands/schedules.ts +33 -22
  267. package/src/commands/scopes.ts +8 -1
  268. package/src/commands/sessions.ts +9 -3
  269. package/src/commands/setup.ts +5 -4
  270. package/src/commands/update.ts +28 -12
  271. package/src/commands/webhooks.ts +30 -19
  272. package/src/completions.ts +25 -13
  273. package/src/config.ts +141 -9
  274. package/src/context.ts +34 -7
  275. package/src/docs/cli-reference.ts +206 -0
  276. package/src/exit-codes.ts +122 -0
  277. package/src/genui.ts +1398 -0
  278. package/src/harnesses.ts +2 -1
  279. package/src/jq.ts +109 -0
  280. package/src/login-offer.ts +6 -2
  281. package/src/manifest.ts +134 -0
  282. package/src/model-auth.ts +173 -0
  283. package/src/model-settings.ts +222 -0
  284. package/src/money.ts +5 -1
  285. package/src/output.ts +60 -0
  286. package/src/runtime.ts +1 -1
  287. package/src/scaffold.ts +2 -1
  288. package/src/validators.ts +18 -11
  289. package/src/version-check.ts +1 -1
  290. package/dist/commands/model-keys.d.ts +0 -22
  291. package/dist/commands/model-keys.js +0 -222
  292. package/dist/commands/model-keys.js.map +0 -1
  293. package/src/commands/model-keys.ts +0 -278
package/dist/cli.js CHANGED
@@ -5,7 +5,7 @@ import * as readline from "node:readline";
5
5
  import { Argument, Command, InvalidArgumentError, Option } from "commander";
6
6
  import { API_KEY_SCOPES } from "@dharta/sdk";
7
7
  import { buildContext } from "./context.js";
8
- import { resolveBaseUrl } from "./config.js";
8
+ import { requestedProfileName, resolveBaseUrl, setRequestedIdempotencyKey, setRequestedProfile, } from "./config.js";
9
9
  import { inferAgentSlug, validateAgentSelectorOptions, validateAgentSlug } from "./agent.js";
10
10
  import { login } from "./commands/login.js";
11
11
  import { authLogout, authLogoutData, authStatus, authStatusData, authToken, } from "./commands/auth.js";
@@ -13,18 +13,22 @@ import { whoami, whoamiData } from "./commands/whoami.js";
13
13
  import { api as apiCmd, formatApiResult, prepareApiOptions, validateApiRequest } from "./commands/api.js";
14
14
  import { auditLog, auditLogData, validateAuditLogInput } from "./commands/audit-log.js";
15
15
  import { COST_ANALYTICS_GROUPS, COST_ANALYTICS_RANGES, ENTITY_ANALYTICS_RANGES, analytics, analyticsData, normalizeAnalyticsOptions, } from "./commands/analytics.js";
16
- import { keysCreate, keysCreateData, keysList, keysListData, keysRename, keysRenameData, keysRevoke, keysRevokeData, validateKeysCreateInput, } from "./commands/keys.js";
17
- import { modelKeysCreate, modelKeysCreateData, modelKeysList, modelKeysListData, modelKeysRevoke, modelKeysRevokeData, prepareModelKeysCreateOptions, MODEL_API_FORMATS, validateModelKeyId, validateModelKeysCreateOptions, } from "./commands/model-keys.js";
18
- import { membersInvite, membersInviteData, membersList, membersListData, membersRemove, membersRemoveData, membersSetRole, membersSetRoleData, validateMembersInviteInput, } from "./commands/members.js";
19
- import { kartaMembersGrant, kartaMembersGrantData, kartaMembersRevoke, kartaMembersRevokeData, kartaMembersSetRole, kartaMembersSetRoleData, kartasArchive, kartasArchiveData, kartasConfigure, kartasConfigureData, kartasRestore, kartasRestoreData, kartasCreate, kartasCreateData, kartasList, kartasListData, kartasName, kartasNameData, kartasShow, kartasShowData, kartaEnvList, kartaEnvListData, kartaEnvSet, kartaEnvSetData, kartaEnvUnset, kartaEnvUnsetData, validateKartaCreateOptions, validateKartaConfigureOptions, validateKartaNameOptions, } from "./commands/kartas.js";
16
+ import { keysBulk, keysBulkData, keysCreate, keysCreateData, keysDisable, keysDisableData, keysEnable, keysEnableData, keysList, keysListData, keysRename, keysRenameData, keysRevoke, keysRevokeData, keysRotate, keysRotateData, KEY_BULK_ACTIONS, KEY_ROTATION_GRACE_PERIODS, validateKeysBulkInput, validateKeysCreateInput, validateKeysRotateInput, } from "./commands/keys.js";
17
+ import { modelConnectionsConfigureModels, modelConnectionsConfigureModelsData, modelConnectionsCreate, modelConnectionsCreateData, modelConnectionsList, modelConnectionsListData, modelConnectionsModels, modelConnectionsModelsData, modelConnectionsModelsWritesOffers, modelConnectionsRevoke, modelConnectionsRevokeData, modelConnectionsRotate, modelConnectionsRotateData, prepareModelConnectionsCreateOptions, prepareModelConnectionsModelsOptions, prepareModelConnectionsRotateOptions, MODEL_API_FORMATS, validateModelConnectionReference, validateModelConnectionsCreateOptions, validateModelConnectionsModelsOptions, validateModelConnectionsRotateOptions, } from "./commands/model-connections.js";
18
+ import { ORG_ENDPOINT_KINDS, orgModelSet, orgModelSetData, orgModelShow, orgModelShowData, validateOrgModelSetOptions, } from "./commands/organization.js";
19
+ import { membersInvite, membersInviteData, membersList, membersListData, membersRemove, membersRemoveData, membersResendInvitation, membersResendInvitationData, membersRevokeInvitation, membersRevokeInvitationData, membersSetRole, membersSetRoleData, validateMembersInviteInput, } from "./commands/members.js";
20
+ import { orgRename, orgRenameData, orgSupportAccess, orgSupportAccessData, orgTranscriptAccess, orgTranscriptAccessData, normalizeOrganizationName, } from "./commands/org.js";
21
+ import { reposDisconnectGithub, reposDisconnectGithubData } from "./commands/repos.js";
22
+ import { kartaMembersGrant, kartaMembersGrantData, kartaMembersRevoke, kartaMembersRevokeData, kartaMembersSetRole, kartaMembersSetRoleData, kartasArchive, kartasArchiveData, kartasConfigure, kartasConfigureData, kartasRestore, kartasRestoreData, kartasCreate, kartasCreateData, kartasList, kartasListData, kartasName, kartasNameData, kartasShow, kartasShowData, kartaEnvList, kartaEnvListData, kartaEnvSet, kartaEnvSetData, kartaEnvUnset, kartaEnvUnsetData, kartaShare, kartaShareData, kartaUnshare, kartaUnshareData, validateKartaCreateOptions, validateKartaConfigureOptions, validateKartaNameOptions, } from "./commands/kartas.js";
20
23
  import { usage as usageCmd, usageData } from "./commands/usage.js";
21
- import { agentsActivateRelease, agentsActivateReleaseData, agentsDashboardEditsSet, agentsDashboardEditsSetData, agentsDelete, agentsDeleteData, agentsList, agentsListData, agentsModelSet, agentsModelSetData, agentsReleases, agentsReleasesData, agentsShow, agentsShowData, agentsServingSet, agentsServingSetData, agentsWorkspaceInspectableSet, agentsWorkspaceInspectableSetData, agentsWorkspaceAccessShow, agentsWorkspaceAccessShowData, agentsWorkspaceAccessSet, agentsWorkspaceAccessSetData, parseWorkspaceAccessAssignments, validateAgentModelSetOptions, } from "./commands/agents.js";
24
+ import { agentsActivateRelease, agentsActivateReleaseData, agentsCreate, agentsCreateData, agentsCreateFromTemplate, agentsCreateFromTemplateData, agentsDashboardEditsSet, agentsDashboardEditsSetData, agentsDelete, agentsDeleteData, agentsDurableWorkspaceSet, agentsDurableWorkspaceSetData, agentsGithubRepos, agentsGithubReposData, agentsList, agentsListData, agentsRedeploy, agentsRedeployData, agentsRename, agentsRenameData, agentsRetryRelease, agentsRetryReleaseData, agentsModelSet, agentsModelSetData, agentsReleases, agentsReleasesData, agentsShow, agentsShowData, agentsServingSet, agentsServingSetData, agentsWorkspaceInspectableSet, agentsWorkspaceInspectableSetData, agentsWorkspaceAccessShow, agentsWorkspaceAccessShowData, agentsWorkspaceAccessSet, agentsWorkspaceAccessSetData, parseWorkspaceAccessAssignments, validateAgentCreateFromTemplateInput, validateAgentCreateInput, validateAgentModelSetOptions, } from "./commands/agents.js";
22
25
  import { embedKeysClearIdentity, embedKeysClearIdentityData, embedKeysCreate, embedKeysCreateData, embedKeysList, embedKeysListData, embedKeysRevoke, embedKeysRevokeData, embedKeysRotate, embedKeysRotateData, embedKeysSetIdentity, embedKeysSetIdentityData, embedKeysToggle, embedKeysToggleData, parseOrigins, validateEmbedKeysCreateInput, } from "./commands/embed-keys.js";
23
26
  import { capsEndUser, capsEndUserData, capsEndUserSet, capsEndUserSetData, capsBudget, capsBudgetData, capsBudgetSet, capsBudgetSetData, capsInstance, capsInstanceData, capsInstanceSet, capsInstanceSetData, capsSeat, capsSeatData, capsSeatSet, capsSeatSetData, validateBudgetSetOptions, validateCapSetOptions, } from "./commands/caps.js";
24
27
  import { appearanceGet, appearanceGetData, appearanceSet, appearanceSetData, validateAppearanceSetInput, } from "./commands/appearance.js";
25
28
  import { schedulesAction, schedulesActionData, schedulesCreate, schedulesCreateData, schedulesDelete, schedulesDeleteData, schedulesList, schedulesListData, validateSchedulesCreateInput, } from "./commands/schedules.js";
26
29
  import { directoryEndUsers, directoryEndUsersData, directoryInstances, directoryInstancesData, directorySessions, directorySessionsData, validateDirectoryOptions, } from "./commands/directories.js";
27
- import { parseEvents, webhooksCreate, webhooksCreateData, webhooksDelete, webhooksDeleteData, webhooksEnable, webhooksEnableData, webhooksList, webhooksListData, webhooksUpdate, webhooksUpdateData, validateWebhooksCreateInput, validateWebhooksUpdateInput, } from "./commands/webhooks.js";
30
+ import { FLEET_ENTITY_TYPES, FLEET_SELECTION_MODES, FLEET_SNOOZE_DURATIONS, FLEET_VIEW_VISIBILITIES, fleetAnalyticsSave, fleetAnalyticsSaveData, fleetAnalyticsUnpin, fleetAnalyticsUnpinData, fleetExportCreate, fleetExportCreateData, fleetFinding, fleetFindingAssign, fleetFindingAssignData, fleetFindingClassify, fleetFindingClassifyData, fleetFindingData, fleetFindingSnooze, fleetFindingSnoozeData, fleetFindingUpdate, fleetFindingUpdateData, fleetOperationCancel, fleetOperationCancelData, fleetOperationConfirm, fleetOperationConfirmData, fleetOperationCreate, fleetOperationCreateData, fleetOperationRetry, fleetOperationRetryData, fleetRollout, fleetRolloutData, fleetRolloutRollback, fleetRolloutRollbackData, fleetViewCreate, fleetViewCreateData, fleetViewDelete, fleetViewDeleteData, fleetViewFavorite, fleetViewFavoriteData, fleetViewUnfavorite, fleetViewUnfavoriteData, fleetViewUpdate, fleetViewUpdateData, } from "./commands/fleet.js";
31
+ import { parseEvents, webhooksCreate, webhooksCreateData, webhooksDelete, webhooksDeleteData, webhooksEnable, webhooksEnableData, webhooksList, webhooksListData, webhooksTest, webhooksTestData, webhooksUpdate, webhooksUpdateData, validateWebhooksCreateInput, validateWebhooksUpdateInput, } from "./commands/webhooks.js";
28
32
  import { rollback, rollbackData } from "./commands/rollback.js";
29
33
  import { deploy, inferMode, validateDeployDir } from "./commands/deploy.js";
30
34
  import { status, statusData } from "./commands/status.js";
@@ -36,6 +40,8 @@ import { offerLogin } from "./login-offer.js";
36
40
  import { doctor } from "./commands/doctor.js";
37
41
  import { dev as devCmd } from "./commands/dev.js";
38
42
  import { registerArtifactCommands } from "./commands/artifact.js";
43
+ import { registerGenuiCommands } from "./commands/genui.js";
44
+ import { flushJsonPayload, isJson, printJson, resetJsonPayload } from "./output.js";
39
45
  import { isHandoffTarget, open as openCmd, openData, openHandoff, openHandoffData, OPEN_TARGETS_HELP, normalizeOpenTarget, validateOpenTarget, } from "./commands/open.js";
40
46
  import { envDiff, envDiffData, envList, envListData, envPull, envPullData, envSet, envSetData, envUnset, envUnsetData, validateEnvAssignment, validateEnvDiffOptions, validateEnvName, validateEnvPullOptions, } from "./commands/env.js";
41
47
  import { ps as psCmd, psData, run as runCmd, sessionsList, sessionsListData, sessionsShow, sessionsShowData, validateSessionsListOptions, } from "./commands/sessions.js";
@@ -43,35 +49,16 @@ import { update } from "./commands/update.js";
43
49
  import { filesLs, filesLsData, filesGet } from "./commands/files.js";
44
50
  import { gitCredential } from "./commands/git-credential.js";
45
51
  import { bashCompletion, zshCompletion } from "./completions.js";
52
+ import { visibleSubcommands } from "./command-tree.js";
53
+ import { CliUsageError, exitCodeForError, isCommanderError, isNotAuthenticatedError } from "./exit-codes.js";
54
+ import { armJqFilter } from "./jq.js";
46
55
  import { closestChoice, normalizeHttpUrl, normalizeNonBlank, parsePositiveInteger, parseReleaseVersion } from "./validators.js";
56
+ import { DEV_MODEL_AUTH_VALUES, MODEL_CONNECTION_PROVIDERS } from "./model-auth.js";
47
57
  const MEMBER_ROLES = ["owner", "admin", "developer", "billing", "viewer"];
48
58
  const DHARTA_ACCESS_AUDIENCES = ["members", "anonymous", "off"];
49
59
  const DHARTA_MEMBER_ROLES = ["viewer", "participant", "manager"];
50
- const MODEL_KEY_AUTH_TYPES = ["api_key", "oauth_subscription"];
51
- const AGENT_MODEL_SOURCES = ["inherit", "platform"];
52
60
  const CLI_API_KEY_SCOPES = API_KEY_SCOPES;
53
61
  const STATE_HELP = "State values: on/off, enabled/disabled, true/false.";
54
- // --json output (RFC 0013 §3): every command that produces a result
55
- // payload prints it as JSON when --json is set. Progress narration
56
- // (device-flow codes, download logs) moves to stderr so stdout stays
57
- // parseable. Commands whose stdout is a stream, a REPL, a script, or a
58
- // protocol rather than a result payload (dev, logs, completion,
59
- // git-credential, and `deploy --mode git` whose output is the live
60
- // push sideband) reject --json. `deploy --mode folder` returns a
61
- // single payload, so it supports --json.
62
- //
63
- // Mechanics: the flag is registered on every node of the command tree
64
- // so commander's
65
- // outermost option scan consumes it wherever it appears on the line -
66
- // so actions read it through optsWithGlobals() on their Command. Commands
67
- // that always reject JSON keep a hidden parser option so help/completions
68
- // do not advertise an invalid mode.
69
- function isJson(cmd) {
70
- return Boolean(cmd.optsWithGlobals().json);
71
- }
72
- function printJson(payload) {
73
- console.log(JSON.stringify(payload, null, 2));
74
- }
75
62
  function commandOpts(cmd) {
76
63
  return cmd.optsWithGlobals();
77
64
  }
@@ -80,7 +67,7 @@ function validatePositionalAgentSelector(slug, opts) {
80
67
  return;
81
68
  validateAgentSlug(slug, "agent slug");
82
69
  if (opts.agent !== undefined || opts.project !== undefined) {
83
- throw new Error("Use either the positional agent slug or --agent/--project, not both.");
70
+ throw new CliUsageError("Use either the positional agent slug or --agent/--project, not both.");
84
71
  }
85
72
  }
86
73
  function validateCreateInput(pathArg, opts) {
@@ -104,9 +91,69 @@ async function resolveAgentOptions(opts, positionalSlug) {
104
91
  return { ...opts, agent, project: undefined };
105
92
  }
106
93
  function rejectJson(cmd, name) {
107
- if (isJson(cmd)) {
108
- throw new Error(`--json is not supported for \`${name}\` - its output is not a single payload. Run it without --json.`);
109
- }
94
+ if (!isJson(cmd))
95
+ return;
96
+ // --jq is rejected wherever --json is, and for the same reason: there is no
97
+ // payload to filter. Name the flag the user actually passed.
98
+ const flag = cmd.optsWithGlobals().jq !== undefined ? "--jq" : "--json";
99
+ throw new CliUsageError(`${flag} is not supported for \`${name}\` - its output is not a single payload. Run it without ${flag}.`);
100
+ }
101
+ // A command group prints help and issues no request, so an Idempotency-Key on
102
+ // one is a mistake with nowhere to land. Read-only LEAF commands are not
103
+ // rejected: see the P9 entry in the RFC 0048 implementation log for why.
104
+ function rejectIdempotencyKey(cmd, name) {
105
+ if (cmd.optsWithGlobals().idempotencyKey === undefined)
106
+ return;
107
+ throw new CliUsageError(`--idempotency-key is not supported for \`${name}\` - it prints help and sends no request. ` +
108
+ "Put it on the command that performs the mutation.");
109
+ }
110
+ // `--idempotency-key` names an `Idempotency-Key` for a write to the Dharta API.
111
+ // These commands perform no mutation the key could protect, so accepting one
112
+ // would silently ignore it, which is precisely the outcome a caller reaching for
113
+ // the flag is trying to avoid.
114
+ //
115
+ // Several of them DO talk to Dharta, and the message must not claim otherwise:
116
+ //
117
+ // - `login` runs before a credential exists. Its device-flow POSTs carry no
118
+ // key and the server installs no idempotency filter on them, and it then
119
+ // reads `/me` to learn who the new key belongs to. Reads and unprotected
120
+ // POSTs, no mutation.
121
+ // - `create` fetches `/agent_templates` and writes the result to disk.
122
+ // - `setup` writes files, and with `--login` it runs the login flow above.
123
+ // - `auth token` and `auth logout` read and rewrite the local profile.
124
+ // - `genui` builds a bundle, `artifact` spawns a local helper.
125
+ // - `doctor` and `update` talk to the package registry, never to Dharta.
126
+ // - `completion` prints a shell script.
127
+ //
128
+ // Read-only Dharta commands (`ps`, `usage`, `webhooks list`) perform no mutation
129
+ // either and are deliberately NOT refused. They are steps in a run that writes,
130
+ // the header rides along and is ignored server-side, and a script that sets one
131
+ // flag for a whole pipeline should not have to special-case them. The commands
132
+ // below are not that: a caller who puts the key on `dharta login` is expressing
133
+ // an intent it can never honour, so saying so beats accepting it.
134
+ const NON_MUTATING_COMMAND_PATHS = [
135
+ "dharta login",
136
+ "dharta auth token",
137
+ "dharta auth logout",
138
+ "dharta create",
139
+ "dharta setup",
140
+ "dharta genui",
141
+ "dharta artifact",
142
+ "dharta doctor",
143
+ "dharta update",
144
+ "dharta completion",
145
+ ];
146
+ export function isNonMutatingCommandPath(path) {
147
+ return NON_MUTATING_COMMAND_PATHS.some((entry) => path === entry || path.startsWith(`${entry} `));
148
+ }
149
+ function rejectNonMutatingIdempotencyKey(cmd, key) {
150
+ if (key === undefined)
151
+ return;
152
+ const path = commandPath(cmd);
153
+ if (!isNonMutatingCommandPath(path))
154
+ return;
155
+ throw new CliUsageError(`--idempotency-key is not supported for \`${path}\` - it performs no mutation the key could protect. ` +
156
+ "The flag applies to commands that write to the Dharta API.");
110
157
  }
111
158
  function helpOnlyAction(name) {
112
159
  return (...args) => {
@@ -121,6 +168,7 @@ function helpOnlyAction(name) {
121
168
  (suggestion ? ` Did you mean \`${suggestion}\`?` : ""));
122
169
  }
123
170
  rejectJson(cmd, name);
171
+ rejectIdempotencyKey(cmd, name);
124
172
  cmd.outputHelp();
125
173
  };
126
174
  }
@@ -138,23 +186,12 @@ function closestCommand(input, commands) {
138
186
  return closestChoice(input, commands);
139
187
  }
140
188
  function commandSuggestionTokens(cmd) {
141
- return Array.from(new Set(cmd.commands
142
- .filter((child) => !child._hidden)
143
- .flatMap((child) => [child.name(), ...child.aliases()])));
189
+ return Array.from(new Set(visibleSubcommands(cmd).flatMap((child) => [child.name(), ...child.aliases()])));
144
190
  }
145
191
  export function buildProgram() {
146
192
  const program = new Command();
147
- // Commander 12 has no native help groups, so render the top-level command
148
- // list grouped (addHelpText below) and suppress commander's default flat
149
- // list on the ROOT only - subcommand help (e.g. `dharta agent --help`) keeps
150
- // commander's default rendering. `defaultHelp` is captured before the
151
- // override so it supplies the unmodified list for subcommands.
152
- const defaultHelp = program.createHelp();
153
193
  program
154
194
  .name("dharta")
155
- .configureHelp({
156
- visibleCommands: (cmd) => (cmd.parent === null ? [] : defaultHelp.visibleCommands(cmd)),
157
- })
158
195
  .description("Build, run, and deploy AI agents on dharta.ai - one tool from create to open.\n" +
159
196
  "Agents are harness-native folders (Claude Code, OpenCode, DeepAgents, Goose, Codex CLI) plus dharta.toml; `dharta deploy` ships one selected folder.")
160
197
  // Read from package.json so `--version` can never drift from the published
@@ -163,51 +200,8 @@ export function buildProgram() {
163
200
  .version)
164
201
  .addHelpText("after", [
165
202
  "",
166
- "Agent lifecycle",
167
- " create Scaffold a brand-new agent",
168
- " setup Configure an agent here; write dharta.toml",
169
- " dev Preview locally as a user would (hot reload)",
170
- " deploy Deploy this agent folder",
171
- " open Open the live hosted page",
172
- " status Every agent here and its live release",
173
- "",
174
- "Operate",
175
- " sessions Inspect an agent's sessions",
176
- " session View one session transcript",
177
- " ps Sessions active right now",
178
- " logs Stream runtime logs",
179
- " files Read a karta's workspace files",
180
- " send One-shot message to a deployed agent",
181
- " rollback Roll back to a previous release",
182
- " env Environment bindings",
183
- "",
184
- "Manage",
185
- " agent List and show your agents",
186
- " artifact Designate durable workspace work product",
187
- "",
188
- "Account",
189
- " login Sign in (device flow)",
190
- " whoami Show the authenticated principal",
191
- " auth Status, tokens, logout",
192
- " audit-log Export audit events",
193
- " analytics Usage and cost analytics",
194
- " keys API keys",
195
- " model-keys BYOK provider credentials",
196
- " members Organization members and invitations",
197
- " kartas Durable Dharta identity, URLs, and ACLs",
198
- " api Authenticated public API passthrough",
199
- " embed-keys Publishable widget keys",
200
- " caps Spend caps and monthly budget",
201
- " appearance Agent appearance theme",
202
- " schedules Recurring agent runs",
203
- " directories Agent-scoped kartas, users, sessions",
204
- " webhooks Event delivery endpoints",
205
- "",
206
- "Utilities",
207
- " usage · doctor · update · completion",
208
- "",
209
203
  "Golden path: dharta login -> create -> setup -> dev -> deploy -> open",
210
- "Run `karta <command> --help` for details. Docs: https://docs.dharta.ai",
204
+ "Run `dharta <command> --help` for details. Docs: https://docs.dharta.ai",
211
205
  ].join("\n"))
212
206
  .action(helpOnlyAction("dharta"));
213
207
  program
@@ -216,19 +210,17 @@ export function buildProgram() {
216
210
  .option("--with-token", "Read an API key from stdin instead (CI, air-gapped)")
217
211
  .option("--base-url <url>", "Override the API base URL")
218
212
  .option("--git-base-url <url>", "Override the git server base URL")
219
- .option("--profile <name>", "Named profile (default: default)")
220
213
  .action(async (opts, cmd) => {
221
214
  if (opts.baseUrl !== undefined)
222
215
  normalizeHttpUrl(opts.baseUrl, "--base-url");
223
216
  if (opts.gitBaseUrl !== undefined)
224
217
  normalizeHttpUrl(opts.gitBaseUrl, "--git-base-url");
225
- if (opts.profile !== undefined)
226
- normalizeNonBlank(opts.profile, "--profile");
227
218
  const json = isJson(cmd);
228
219
  const result = await login({
229
220
  baseUrl: opts.baseUrl,
230
221
  gitBaseUrl: opts.gitBaseUrl,
231
- profile: opts.profile,
222
+ // The global --profile names the profile this login writes.
223
+ profile: requestedProfileName(),
232
224
  apiKey: opts.withToken ? await readStdin() : undefined,
233
225
  // In JSON mode the device-flow narration (code, approve URL)
234
226
  // still has to reach the human - on stderr.
@@ -269,13 +261,14 @@ export function buildProgram() {
269
261
  });
270
262
  auth
271
263
  .command("logout")
272
- .description("Remove the stored credential (the key stays revocable on the dashboard).")
273
- .option("--profile <name>", "Profile to remove (default: the default profile)")
274
- .action(async (opts, cmd) => {
264
+ .description("Remove the stored credential (the key stays revocable on the dashboard). Removes the default profile unless --profile names another.")
265
+ .action(async (_opts, cmd) => {
266
+ // The global --profile names the profile this removes.
267
+ const profile = requestedProfileName();
275
268
  if (isJson(cmd))
276
- printJson(await authLogoutData(opts.profile));
269
+ printJson(await authLogoutData(profile));
277
270
  else
278
- console.log(await authLogout(opts.profile));
271
+ console.log(await authLogout(profile));
279
272
  });
280
273
  program
281
274
  .command("create [path]")
@@ -311,7 +304,7 @@ export function buildProgram() {
311
304
  .action(async (pathArg, opts, cmd) => {
312
305
  const json = isJson(cmd);
313
306
  if (json && opts.login) {
314
- throw new Error("--login is not supported with `dharta setup --json`. Run `dharta setup --json` first, then `dharta login`.");
307
+ throw new CliUsageError("--login is not supported with `dharta setup --json`. Run `dharta setup --json` first, then `dharta login`.");
315
308
  }
316
309
  const interactive = !json && !opts.yes && process.stdin.isTTY;
317
310
  const rl = interactive
@@ -369,7 +362,7 @@ export function buildProgram() {
369
362
  .action(async (opts, cmd) => {
370
363
  validateAuditLogInput(opts);
371
364
  if (opts.csv && isJson(cmd)) {
372
- throw new Error("Use either --csv or --json for audit-log, not both.");
365
+ throw new CliUsageError("Use either --csv or --json for audit-log, not both.");
373
366
  }
374
367
  const ctx = await buildContext();
375
368
  if (isJson(cmd))
@@ -415,7 +408,8 @@ export function buildProgram() {
415
408
  });
416
409
  program
417
410
  .command("api [method] [path]")
418
- .description("Call an allowlisted public JSON API endpoint with the active profile.")
411
+ .description("Call any public JSON API endpoint with the active profile. Unstable escape hatch: the curated commands are the stable contract, and this passthrough follows the API. " +
412
+ "Reachable paths start with /api/, /me, /version, /api_keys, /model_connections, or /agent_templates; what the request may do is decided server-side by the key's scopes.")
419
413
  .option("-F, --field <key=value>", "Add a JSON-coerced field to the request body", collect, [])
420
414
  .option("-f, --raw-field <key=value>", "Add a string field to the request body", collect, [])
421
415
  .option("-H, --header <name:value>", "Add a safe request header", collect, [])
@@ -482,46 +476,210 @@ export function buildProgram() {
482
476
  else
483
477
  console.log(await keysRevoke(ctx, id));
484
478
  });
485
- const modelKeys = program.command("model-keys").description("Manage BYOK provider credentials.").action(helpOnlyAction("dharta model-keys"));
486
- modelKeys
479
+ keys
480
+ .command("rotate <id>")
481
+ .description("Replace a key with a new one carrying the same scopes, then retire the original.")
482
+ .addOption(choiceOption("--grace-period <window>", "How long the rotated key keeps working (default 24h)", KEY_ROTATION_GRACE_PERIODS))
483
+ .action(async (id, opts, cmd) => {
484
+ validateKeysRotateInput(id, opts);
485
+ const ctx = await buildContext();
486
+ if (isJson(cmd))
487
+ printJson(await keysRotateData(ctx, id, opts));
488
+ else
489
+ console.log(await keysRotate(ctx, id, opts));
490
+ });
491
+ keys
492
+ .command("disable <id>")
493
+ .description("Suspend an API key without revoking it.")
494
+ .action(async (id, _opts, cmd) => {
495
+ normalizeNonBlank(id, "API key id");
496
+ const ctx = await buildContext();
497
+ if (isJson(cmd))
498
+ printJson(await keysDisableData(ctx, id));
499
+ else
500
+ console.log(await keysDisable(ctx, id));
501
+ });
502
+ keys
503
+ .command("enable <id>")
504
+ .description("Return a disabled API key to service.")
505
+ .action(async (id, _opts, cmd) => {
506
+ normalizeNonBlank(id, "API key id");
507
+ const ctx = await buildContext();
508
+ if (isJson(cmd))
509
+ printJson(await keysEnableData(ctx, id));
510
+ else
511
+ console.log(await keysEnable(ctx, id));
512
+ });
513
+ keys
514
+ .command("bulk")
515
+ .description("Apply one state change to several API keys atomically.")
516
+ .addArgument(choiceArgument("<action>", "state change to apply", KEY_BULK_ACTIONS))
517
+ .argument("<id...>", "API key ids")
518
+ .action(async (action, ids, _opts, cmd) => {
519
+ validateKeysBulkInput(action, ids);
520
+ const ctx = await buildContext();
521
+ if (isJson(cmd))
522
+ printJson(await keysBulkData(ctx, action, ids));
523
+ else
524
+ console.log(await keysBulk(ctx, action, ids));
525
+ });
526
+ const models = program
527
+ .command("models")
528
+ .description("Manage model configuration and authentication.")
529
+ .action(helpOnlyAction("dharta models"));
530
+ const modelConnections = models
531
+ .command("auth")
532
+ .description("Manage model provider connections.")
533
+ .action(helpOnlyAction("dharta models auth"));
534
+ modelConnections
487
535
  .command("list")
488
536
  .description("List model provider credentials.")
489
537
  .action(async (_opts, cmd) => {
490
538
  const ctx = await buildContext();
491
539
  if (isJson(cmd))
492
- printJson(await modelKeysListData(ctx));
540
+ printJson(await modelConnectionsListData(ctx));
493
541
  else
494
- console.log(await modelKeysList(ctx));
542
+ console.log(await modelConnectionsList(ctx));
495
543
  });
496
- modelKeys
544
+ modelConnections
497
545
  .command("create")
498
546
  .description("Store an encrypted model provider credential.")
499
- .addArgument(choiceArgument("<provider>", "provider", ["anthropic", "openai", "bedrock", "vertex", "openrouter", "xai", "google"]))
547
+ .addArgument(choiceArgument("<provider>", "provider", MODEL_CONNECTION_PROVIDERS))
500
548
  .argument("<name>", "connector name")
501
549
  .option("--key <plaintext>", "Provider API key plaintext")
502
550
  .option("--key-stdin", "Read provider API key plaintext from stdin")
503
- .addOption(choiceOption("--auth-type <type>", "api_key or oauth_subscription", MODEL_KEY_AUTH_TYPES))
551
+ .option("--slug <slug>", "Connector slug used by --connector and model references (default: derived from the name)")
504
552
  .option("--endpoint-url <url>", "Provider endpoint URL override")
505
553
  .addOption(choiceOption("--api-format <format>", "Explicit provider API format", MODEL_API_FORMATS))
506
554
  .action(async (provider, name, opts, cmd) => {
507
- validateModelKeysCreateOptions(provider, name, opts);
508
- const preparedOpts = await prepareModelKeysCreateOptions(provider, name, opts);
555
+ validateModelConnectionsCreateOptions(provider, name, opts);
556
+ const preparedOpts = await prepareModelConnectionsCreateOptions(provider, name, opts);
509
557
  const ctx = await buildContext();
510
558
  if (isJson(cmd))
511
- printJson(await modelKeysCreateData(ctx, provider, name, preparedOpts));
559
+ printJson(await modelConnectionsCreateData(ctx, provider, name, preparedOpts));
512
560
  else
513
- console.log(await modelKeysCreate(ctx, provider, name, preparedOpts));
561
+ console.log(await modelConnectionsCreate(ctx, provider, name, preparedOpts));
514
562
  });
515
- modelKeys
516
- .command("revoke <id>")
563
+ modelConnections
564
+ .command("rotate <id|slug>")
565
+ .description("Replace a connector's stored credential, keeping its slug and every selection that names it.")
566
+ .option("--key <plaintext>", "New provider API key plaintext")
567
+ .option("--key-stdin", "Read the new provider API key plaintext from stdin")
568
+ .option("--name <name>", "Rename the connector while rotating it")
569
+ .action(async (reference, opts, cmd) => {
570
+ validateModelConnectionsRotateOptions(reference, opts);
571
+ const preparedOpts = await prepareModelConnectionsRotateOptions(reference, opts);
572
+ const ctx = await buildContext();
573
+ if (isJson(cmd))
574
+ printJson(await modelConnectionsRotateData(ctx, reference, preparedOpts));
575
+ else
576
+ console.log(await modelConnectionsRotate(ctx, reference, preparedOpts));
577
+ });
578
+ modelConnections
579
+ .command("models <id|slug>")
580
+ .description("Show the models a connector serves, or replace its enabled set and default.")
581
+ .option("--enable <models>", "Comma-separated model ids to enable; this replaces the whole enabled set")
582
+ .option("--enable-stdin", "Read the model ids to enable from stdin")
583
+ .option("--default <model>", "Connector default model; must be in the enabled set")
584
+ .option("--clear-default", "Leave the connector with no default model")
585
+ .action(async (reference, opts, cmd) => {
586
+ validateModelConnectionsModelsOptions(reference, opts);
587
+ if (!modelConnectionsModelsWritesOffers(opts)) {
588
+ validateModelConnectionReference(reference);
589
+ const readCtx = await buildContext();
590
+ if (isJson(cmd))
591
+ printJson(await modelConnectionsModelsData(readCtx, reference));
592
+ else
593
+ console.log(await modelConnectionsModels(readCtx, reference));
594
+ return;
595
+ }
596
+ const preparedOpts = await prepareModelConnectionsModelsOptions(reference, opts);
597
+ const ctx = await buildContext();
598
+ if (isJson(cmd))
599
+ printJson(await modelConnectionsConfigureModelsData(ctx, reference, preparedOpts));
600
+ else
601
+ console.log(await modelConnectionsConfigureModels(ctx, reference, preparedOpts));
602
+ });
603
+ modelConnections
604
+ .command("revoke <id|slug>")
517
605
  .description("Revoke a model provider credential.")
518
- .action(async (id, _opts, cmd) => {
519
- validateModelKeyId(id);
606
+ .action(async (reference, _opts, cmd) => {
607
+ validateModelConnectionReference(reference);
608
+ const ctx = await buildContext();
609
+ if (isJson(cmd))
610
+ printJson(await modelConnectionsRevokeData(ctx, reference));
611
+ else
612
+ console.log(await modelConnectionsRevoke(ctx, reference));
613
+ });
614
+ const org = program
615
+ .command("org")
616
+ .description("Manage organization settings.")
617
+ .action(helpOnlyAction("dharta org"));
618
+ const orgModel = org
619
+ .command("model")
620
+ .description("Show the organization connector order, model reference, parameters, and what they resolve to.")
621
+ .action(async (_opts, cmd) => {
622
+ const ctx = await buildContext();
623
+ if (isJson(cmd))
624
+ printJson(await orgModelShowData(ctx));
625
+ else
626
+ console.log(await orgModelShow(ctx));
627
+ });
628
+ orgModel
629
+ .command("set")
630
+ .description("Update the organization connector order, model reference, endpoint override, and portable model parameters.")
631
+ .option("--connector <slugs>", "Ordered connector slugs from `dharta models auth list`, or an empty string to unset")
632
+ .option("--model-ref <reference>", "Model reference: <model>, connector:<slug>/<model>, or an empty string to unset")
633
+ .option("--endpoint-url <url>", "Public HTTPS endpoint to call instead of the provider's standard API, or an empty string to clear")
634
+ .addOption(choiceOption("--endpoint-kind <kind>", "Wire protocol for --endpoint-url", ORG_ENDPOINT_KINDS))
635
+ .option("--temperature <number>", "Sampling temperature from 0 to 2")
636
+ .option("--clear-temperature", "Clear the organization temperature")
637
+ .option("--top-p <number>", "Nucleus sampling probability above 0 and at most 1")
638
+ .option("--clear-top-p", "Clear the organization top-p")
639
+ .option("--max-output-tokens <number>", "Positive output token limit")
640
+ .option("--clear-max-output-tokens", "Clear the organization output token limit")
641
+ .addOption(choiceOption("--reasoning-effort <level>", "Reasoning effort", ["low", "medium", "high"]))
642
+ .option("--clear-reasoning-effort", "Clear the organization reasoning effort")
643
+ .action(async (opts, cmd) => {
644
+ validateOrgModelSetOptions(opts);
520
645
  const ctx = await buildContext();
521
646
  if (isJson(cmd))
522
- printJson(await modelKeysRevokeData(ctx, id));
647
+ printJson(await orgModelSetData(ctx, opts));
523
648
  else
524
- console.log(await modelKeysRevoke(ctx, id));
649
+ console.log(await orgModelSet(ctx, opts));
650
+ });
651
+ org
652
+ .command("rename <name>")
653
+ .description("Change the organization display name. The slug never changes.")
654
+ .action(async (name, _opts, cmd) => {
655
+ normalizeOrganizationName(name);
656
+ const ctx = await buildContext();
657
+ if (isJson(cmd))
658
+ printJson(await orgRenameData(ctx, name));
659
+ else
660
+ console.log(await orgRename(ctx, name));
661
+ });
662
+ org
663
+ .command("support-access <state>")
664
+ .description(`Allow or block Dharta support access to session content. ${STATE_HELP}`)
665
+ .action(async (state, _opts, cmd) => {
666
+ const allowed = parseOnOff(state, "state");
667
+ const ctx = await buildContext();
668
+ if (isJson(cmd))
669
+ printJson(await orgSupportAccessData(ctx, allowed));
670
+ else
671
+ console.log(await orgSupportAccess(ctx, allowed));
672
+ });
673
+ org
674
+ .command("transcript-access <state>")
675
+ .description(`Allow or block API keys from reading end-user transcripts. ${STATE_HELP}`)
676
+ .action(async (state, _opts, cmd) => {
677
+ const enabled = parseOnOff(state, "state");
678
+ const ctx = await buildContext();
679
+ if (isJson(cmd))
680
+ printJson(await orgTranscriptAccessData(ctx, enabled));
681
+ else
682
+ console.log(await orgTranscriptAccess(ctx, enabled));
525
683
  });
526
684
  const members = program.command("members").description("Manage organization members.").action(helpOnlyAction("dharta members"));
527
685
  members
@@ -540,7 +698,7 @@ export function buildProgram() {
540
698
  .addOption(choiceOption("--role <role>", "owner, admin, developer, billing, or viewer", MEMBER_ROLES))
541
699
  .action(async (email, opts, cmd) => {
542
700
  if (opts.role === undefined) {
543
- throw new Error("--role is required. Usage: dharta members invite <email> --role <role>");
701
+ throw new CliUsageError("--role is required. Usage: dharta members invite <email> --role <role>");
544
702
  }
545
703
  validateMembersInviteInput(email);
546
704
  const ctx = await buildContext();
@@ -555,7 +713,7 @@ export function buildProgram() {
555
713
  .addOption(choiceOption("--role <role>", "owner, admin, developer, billing, or viewer", MEMBER_ROLES))
556
714
  .action(async (id, opts, cmd) => {
557
715
  if (opts.role === undefined) {
558
- throw new Error("--role is required. Usage: dharta members set-role <id> --role <role>");
716
+ throw new CliUsageError("--role is required. Usage: dharta members set-role <id> --role <role>");
559
717
  }
560
718
  parsePositiveInteger(id, "member id");
561
719
  const ctx = await buildContext();
@@ -575,6 +733,40 @@ export function buildProgram() {
575
733
  else
576
734
  console.log(await membersRemove(ctx, id));
577
735
  });
736
+ members
737
+ .command("revoke-invitation <id>")
738
+ .description("Revoke a pending invitation.")
739
+ .action(async (id, _opts, cmd) => {
740
+ parsePositiveInteger(id, "invitation id");
741
+ const ctx = await buildContext();
742
+ if (isJson(cmd))
743
+ printJson(await membersRevokeInvitationData(ctx, id));
744
+ else
745
+ console.log(await membersRevokeInvitation(ctx, id));
746
+ });
747
+ members
748
+ .command("resend-invitation <id>")
749
+ .description("Re-send a pending invitation, keeping the original link.")
750
+ .action(async (id, _opts, cmd) => {
751
+ parsePositiveInteger(id, "invitation id");
752
+ const ctx = await buildContext();
753
+ if (isJson(cmd))
754
+ printJson(await membersResendInvitationData(ctx, id));
755
+ else
756
+ console.log(await membersResendInvitation(ctx, id));
757
+ });
758
+ const repos = program.command("repos").description("Manage hosted source repositories.").action(helpOnlyAction("dharta repos"));
759
+ repos
760
+ .command("disconnect-github <slug>")
761
+ .description("Stop a GitHub repository from producing releases. Live releases are untouched.")
762
+ .action(async (slug, _opts, cmd) => {
763
+ validateAgentSlug(slug, "source repo slug");
764
+ const ctx = await buildContext();
765
+ if (isJson(cmd))
766
+ printJson(await reposDisconnectGithubData(ctx, slug));
767
+ else
768
+ console.log(await reposDisconnectGithub(ctx, slug));
769
+ });
578
770
  const kartas = program.command("kartas").description("Manage durable kartas and virtual employees.").action(helpOnlyAction("dharta kartas"));
579
771
  kartas
580
772
  .command("create <name>")
@@ -720,7 +912,7 @@ export function buildProgram() {
720
912
  .addOption(choiceOption("--role <role>", "viewer, participant, or manager", DHARTA_MEMBER_ROLES))
721
913
  .action(async (id, membershipId, opts, cmd) => {
722
914
  if (opts.role === undefined) {
723
- throw new Error("--role is required. Usage: dharta kartas set-role <id> <membership-id> --role <role>");
915
+ throw new CliUsageError("--role is required. Usage: dharta kartas set-role <id> <membership-id> --role <role>");
724
916
  }
725
917
  const ctx = await buildContext();
726
918
  if (isJson(cmd))
@@ -728,6 +920,29 @@ export function buildProgram() {
728
920
  else
729
921
  console.log(await kartaMembersSetRole(ctx, id, membershipId, opts.role));
730
922
  });
923
+ kartas
924
+ .command("share <id>")
925
+ .description("Mint a no-sign-in link to a karta and reveal it once.")
926
+ .action(async (id, _opts, cmd) => {
927
+ normalizeNonBlank(id, "karta id");
928
+ const ctx = await buildContext();
929
+ if (isJson(cmd))
930
+ printJson(await kartaShareData(ctx, id));
931
+ else
932
+ console.log(await kartaShare(ctx, id));
933
+ });
934
+ kartas
935
+ .command("unshare <id> <share-id>")
936
+ .description("Revoke a karta share link.")
937
+ .action(async (id, shareId, _opts, cmd) => {
938
+ normalizeNonBlank(id, "karta id");
939
+ normalizeNonBlank(shareId, "share id");
940
+ const ctx = await buildContext();
941
+ if (isJson(cmd))
942
+ printJson(await kartaUnshareData(ctx, id, shareId));
943
+ else
944
+ console.log(await kartaUnshare(ctx, id, shareId));
945
+ });
731
946
  kartas
732
947
  .command("revoke <id> <membership-id>")
733
948
  .description("Remove a person's access to a dharta.")
@@ -954,7 +1169,7 @@ export function buildProgram() {
954
1169
  console.log(await appearanceGet(ctx, resolved));
955
1170
  });
956
1171
  appearanceOpts(appearance.command("set"))
957
- .description("Merge appearance JSON from a local file.")
1172
+ .description("Merge appearance JSON from a local file. A token set to null in the file is cleared and falls back to the preset.")
958
1173
  .option("--file <file>", "JSON file containing appearance tokens")
959
1174
  .action(async (_opts, cmd) => {
960
1175
  const opts = commandOpts(cmd);
@@ -1070,6 +1285,262 @@ export function buildProgram() {
1070
1285
  else
1071
1286
  console.log(await directorySessions(ctx, resolved));
1072
1287
  });
1288
+ // `fleet` mirrors the fleet console's write side. Reads live under
1289
+ // `directories` and `analytics`; everything here changes something.
1290
+ const fleet = program.command("fleet").description("Run fleet-wide changes, triage, and exports.").action(helpOnlyAction("dharta fleet"));
1291
+ const fleetOperations = fleet.command("operations").description("Preview and apply bulk fleet changes.").action(helpOnlyAction("dharta fleet operations"));
1292
+ fleetOperations
1293
+ .command("create")
1294
+ .description("Freeze a selection into a draft operation. Nothing is applied until you confirm it.")
1295
+ .option("--action <key>", "Action to run, for example set_lifecycle or pause_serving")
1296
+ .option("--entity-type <type>", `Entity type (${FLEET_ENTITY_TYPES.join(", ")})`)
1297
+ .option("--selection-mode <mode>", `How targets are chosen (${FLEET_SELECTION_MODES.join(", ")})`)
1298
+ .option("--id <id...>", "Target row id; repeat for more")
1299
+ .option("--saved-view <id>", "Take the targets from a saved view")
1300
+ .option("--filter <query>", "Take the targets from a catalog filter")
1301
+ .option("--param <key=value...>", "Action parameter; repeat for more")
1302
+ .action(async (opts, cmd) => {
1303
+ const ctx = await buildContext();
1304
+ if (isJson(cmd))
1305
+ printJson(await fleetOperationCreateData(ctx, opts));
1306
+ else
1307
+ console.log(await fleetOperationCreate(ctx, opts));
1308
+ });
1309
+ fleetOperations
1310
+ .command("confirm <id>")
1311
+ .description("Apply a draft operation. Needs fleet:operations:write.")
1312
+ .option("--phrase <phrase>", "The confirmation phrase the draft returned")
1313
+ .action(async (id, opts, cmd) => {
1314
+ const ctx = await buildContext();
1315
+ if (isJson(cmd))
1316
+ printJson(await fleetOperationConfirmData(ctx, id, opts.phrase));
1317
+ else
1318
+ console.log(await fleetOperationConfirm(ctx, id, opts.phrase));
1319
+ });
1320
+ fleetOperations
1321
+ .command("cancel <id>")
1322
+ .description("Stop an operation's remaining targets. Needs fleet:operations:write.")
1323
+ .action(async (id, _opts, cmd) => {
1324
+ const ctx = await buildContext();
1325
+ if (isJson(cmd))
1326
+ printJson(await fleetOperationCancelData(ctx, id));
1327
+ else
1328
+ console.log(await fleetOperationCancel(ctx, id));
1329
+ });
1330
+ fleetOperations
1331
+ .command("retry <id>")
1332
+ .description("Requeue only the failed targets. Needs fleet:operations:write.")
1333
+ .action(async (id, _opts, cmd) => {
1334
+ const ctx = await buildContext();
1335
+ if (isJson(cmd))
1336
+ printJson(await fleetOperationRetryData(ctx, id));
1337
+ else
1338
+ console.log(await fleetOperationRetry(ctx, id));
1339
+ });
1340
+ const fleetRollouts = fleet.command("rollouts").description("Drive a staged release rollout.").action(helpOnlyAction("dharta fleet rollouts"));
1341
+ // Every rollout verb needs fleet:operations:write, not just the two the
1342
+ // console gates with a step-up: pausing or resuming a release mid-flight
1343
+ // moves live releases the same way advancing it does.
1344
+ for (const [verb, description] of [
1345
+ ["advance", "Move the rollout to its next ring. Needs fleet:operations:write."],
1346
+ ["pause", "Hold the rollout where it is. Needs fleet:operations:write."],
1347
+ ["resume", "Resume a paused rollout. Needs fleet:operations:write."],
1348
+ [
1349
+ "evaluate",
1350
+ "Run the health evaluation now instead of waiting for the window. Needs fleet:operations:write.",
1351
+ ],
1352
+ ]) {
1353
+ fleetRollouts
1354
+ .command(`${verb} <id>`)
1355
+ .description(description)
1356
+ .action(async (id, _opts, cmd) => {
1357
+ const ctx = await buildContext();
1358
+ if (isJson(cmd))
1359
+ printJson(await fleetRolloutData(ctx, verb, id));
1360
+ else
1361
+ console.log(await fleetRollout(ctx, verb, id));
1362
+ });
1363
+ }
1364
+ fleetRollouts
1365
+ .command("rollback <id>")
1366
+ .description("Revert every target to the previous release. Needs fleet:operations:write.")
1367
+ .action(async (id, _opts, cmd) => {
1368
+ const ctx = await buildContext();
1369
+ if (isJson(cmd))
1370
+ printJson(await fleetRolloutRollbackData(ctx, id));
1371
+ else
1372
+ console.log(await fleetRolloutRollback(ctx, id));
1373
+ });
1374
+ const fleetFindings = fleet.command("findings").description("Triage anomaly findings.").action(helpOnlyAction("dharta fleet findings"));
1375
+ for (const [verb, description] of [
1376
+ ["acknowledge", "Take ownership of a finding."],
1377
+ ["resolve", "Close a finding."],
1378
+ ["reopen", "Reopen a resolved or snoozed finding."],
1379
+ ["promote", "Raise a finding to an incident."],
1380
+ ]) {
1381
+ fleetFindings
1382
+ .command(`${verb} <id>`)
1383
+ .description(description)
1384
+ .action(async (id, _opts, cmd) => {
1385
+ const ctx = await buildContext();
1386
+ if (isJson(cmd))
1387
+ printJson(await fleetFindingData(ctx, verb, id));
1388
+ else
1389
+ console.log(await fleetFinding(ctx, verb, id));
1390
+ });
1391
+ }
1392
+ fleetFindings
1393
+ .command("snooze <id>")
1394
+ .description("Hide a finding until the window is up.")
1395
+ .option("--duration <window>", `Snooze window (${FLEET_SNOOZE_DURATIONS.join(", ")})`)
1396
+ .action(async (id, opts, cmd) => {
1397
+ const ctx = await buildContext();
1398
+ if (isJson(cmd))
1399
+ printJson(await fleetFindingSnoozeData(ctx, id, opts));
1400
+ else
1401
+ console.log(await fleetFindingSnooze(ctx, id, opts));
1402
+ });
1403
+ fleetFindings
1404
+ .command("classify <id>")
1405
+ .description("Record what a finding turned out to be.")
1406
+ .option("--as <classification>", "Classification to record")
1407
+ .action(async (id, opts, cmd) => {
1408
+ const ctx = await buildContext();
1409
+ if (isJson(cmd))
1410
+ printJson(await fleetFindingClassifyData(ctx, id, opts));
1411
+ else
1412
+ console.log(await fleetFindingClassify(ctx, id, opts));
1413
+ });
1414
+ fleetFindings
1415
+ .command("assign <id>")
1416
+ .description("Assign a finding to a member, or clear the owner.")
1417
+ .option("--membership-id <id>", "Organization membership id to assign")
1418
+ .option("--unassign", "Clear the current owner")
1419
+ .action(async (id, opts, cmd) => {
1420
+ const ctx = await buildContext();
1421
+ if (isJson(cmd))
1422
+ printJson(await fleetFindingAssignData(ctx, id, opts));
1423
+ else
1424
+ console.log(await fleetFindingAssign(ctx, id, opts));
1425
+ });
1426
+ fleetFindings
1427
+ .command("update <id>")
1428
+ .description("Set or clear a finding's runbook link.")
1429
+ .option("--runbook-url <url>", "Runbook URL; pass an empty string to clear")
1430
+ .action(async (id, opts, cmd) => {
1431
+ const ctx = await buildContext();
1432
+ if (isJson(cmd))
1433
+ printJson(await fleetFindingUpdateData(ctx, id, opts));
1434
+ else
1435
+ console.log(await fleetFindingUpdate(ctx, id, opts));
1436
+ });
1437
+ const fleetViews = fleet.command("views").description("Manage saved fleet views.").action(helpOnlyAction("dharta fleet views"));
1438
+ const viewWriteOpts = (cmd) => cmd
1439
+ .option("--entity-type <type>", "Entity type the view lists")
1440
+ .option("--name <name>", "View name")
1441
+ .option("--definition <json>", "Filters, columns and sort, as a JSON object")
1442
+ .option("--description <text>", "What the view is for")
1443
+ .option("--visibility <level>", `Who can see it (${FLEET_VIEW_VISIBILITIES.join(", ")})`)
1444
+ .option("--team-id <id>", "Owning team, for team visibility")
1445
+ .option("--organization-default", "Make it the organization's default view");
1446
+ viewWriteOpts(fleetViews.command("create"))
1447
+ .description("Create a saved view.")
1448
+ .action(async (opts, cmd) => {
1449
+ const ctx = await buildContext();
1450
+ if (isJson(cmd))
1451
+ printJson(await fleetViewCreateData(ctx, opts));
1452
+ else
1453
+ console.log(await fleetViewCreate(ctx, opts));
1454
+ });
1455
+ viewWriteOpts(fleetViews.command("update <id>"))
1456
+ .description("Change a saved view.")
1457
+ .action(async (id, opts, cmd) => {
1458
+ const ctx = await buildContext();
1459
+ if (isJson(cmd))
1460
+ printJson(await fleetViewUpdateData(ctx, id, opts));
1461
+ else
1462
+ console.log(await fleetViewUpdate(ctx, id, opts));
1463
+ });
1464
+ fleetViews
1465
+ .command("delete <id>")
1466
+ .alias("rm")
1467
+ .description("Delete a saved view.")
1468
+ .action(async (id, _opts, cmd) => {
1469
+ const ctx = await buildContext();
1470
+ if (isJson(cmd))
1471
+ printJson(await fleetViewDeleteData(ctx, id));
1472
+ else
1473
+ console.log(await fleetViewDelete(ctx, id));
1474
+ });
1475
+ fleetViews
1476
+ .command("favorite <id>")
1477
+ .description("Favorite a saved view for the key's owner.")
1478
+ .action(async (id, _opts, cmd) => {
1479
+ const ctx = await buildContext();
1480
+ if (isJson(cmd))
1481
+ printJson(await fleetViewFavoriteData(ctx, id));
1482
+ else
1483
+ console.log(await fleetViewFavorite(ctx, id));
1484
+ });
1485
+ fleetViews
1486
+ .command("unfavorite <id>")
1487
+ .description("Remove a saved view from the key owner's favorites.")
1488
+ .action(async (id, _opts, cmd) => {
1489
+ const ctx = await buildContext();
1490
+ if (isJson(cmd))
1491
+ printJson(await fleetViewUnfavoriteData(ctx, id));
1492
+ else
1493
+ console.log(await fleetViewUnfavorite(ctx, id));
1494
+ });
1495
+ const fleetAnalytics = fleet.command("analytics").description("Save and unpin Analytics charts.").action(helpOnlyAction("dharta fleet analytics"));
1496
+ fleetAnalytics
1497
+ .command("save")
1498
+ .description("Save an explorer chart and pin it to your Analytics list.")
1499
+ .option("--name <name>", "Chart name")
1500
+ .option("--metric <metric>", "Metric to chart. Defaults to turns.")
1501
+ .option("--description <text>", "What the chart shows")
1502
+ .option("--range <range>", "Time range, for example 30d")
1503
+ .option("--starts-at <timestamp>", "Custom range start")
1504
+ .option("--ends-at <timestamp>", "Custom range end")
1505
+ .option("--scope-kind <kind>", "Scope the chart to a kind of row")
1506
+ .option("--scope-ids <ids>", "Comma-separated scope ids")
1507
+ .option("--bucket <bucket>", "Time bucket, for example day")
1508
+ .option("--aggregation <aggregation>", "How values are combined")
1509
+ .option("--comparison <comparison>", "Comparison series to draw")
1510
+ .option("--comparison-saved-view <id>", "Saved cohort to compare against")
1511
+ .option("--breakdown <field...>", "Break the series down by a field; repeat for more")
1512
+ .option("--event <type...>", "Event type to include; repeat for more")
1513
+ .option("--filter <key=value...>", "Filter; repeat for more")
1514
+ .action(async (opts, cmd) => {
1515
+ const ctx = await buildContext();
1516
+ if (isJson(cmd))
1517
+ printJson(await fleetAnalyticsSaveData(ctx, opts));
1518
+ else
1519
+ console.log(await fleetAnalyticsSave(ctx, opts));
1520
+ });
1521
+ fleetAnalytics
1522
+ .command("unpin <id>")
1523
+ .description("Remove a chart from your Analytics list. The saved view survives.")
1524
+ .action(async (id, _opts, cmd) => {
1525
+ const ctx = await buildContext();
1526
+ if (isJson(cmd))
1527
+ printJson(await fleetAnalyticsUnpinData(ctx, id));
1528
+ else
1529
+ console.log(await fleetAnalyticsUnpin(ctx, id));
1530
+ });
1531
+ const fleetExports = fleet.command("exports").description("Export catalog rows as CSV.").action(helpOnlyAction("dharta fleet exports"));
1532
+ fleetExports
1533
+ .command("create")
1534
+ .description("Write the named rows to stdout as CSV.")
1535
+ .option("--entity-type <type>", `Entity type (${FLEET_ENTITY_TYPES.join(", ")})`)
1536
+ .option("--id <id...>", "Row id to export; repeat for more")
1537
+ .action(async (opts, cmd) => {
1538
+ const ctx = await buildContext();
1539
+ if (isJson(cmd))
1540
+ printJson(await fleetExportCreateData(ctx, opts));
1541
+ else
1542
+ console.log(await fleetExportCreate(ctx, opts));
1543
+ });
1073
1544
  const webhooks = program.command("webhooks").description("Manage webhook endpoints.").action(helpOnlyAction("dharta webhooks"));
1074
1545
  webhooks
1075
1546
  .command("list")
@@ -1120,6 +1591,17 @@ export function buildProgram() {
1120
1591
  else
1121
1592
  console.log(await webhooksEnable(ctx, id));
1122
1593
  });
1594
+ webhooks
1595
+ .command("test <id>")
1596
+ .description("Send one test event through the real delivery path.")
1597
+ .action(async (id, _opts, cmd) => {
1598
+ normalizeNonBlank(id, "Webhook endpoint id");
1599
+ const ctx = await buildContext();
1600
+ if (isJson(cmd))
1601
+ printJson(await webhooksTestData(ctx, id));
1602
+ else
1603
+ console.log(await webhooksTest(ctx, id));
1604
+ });
1123
1605
  webhooks
1124
1606
  .command("delete <id>")
1125
1607
  .alias("rm")
@@ -1168,6 +1650,7 @@ export function buildProgram() {
1168
1650
  .option("--user <id>", "Simulate a verified end user (per-user memory behavior)")
1169
1651
  .option("--port <port>", "Serve the local agent API on a stable port (for widgets/frontends)")
1170
1652
  .option("--verbose", "Stream agent-runtime output and parity details")
1653
+ .addOption(choiceOption("--model-auth <method>", "Anthropic authentication: api-key or claude", DEV_MODEL_AUTH_VALUES))
1171
1654
  .option("--release <vN>", "Run the exact built tree prod serves (audited archive pull)")
1172
1655
  .addOption(choiceOption("--env <mode>", "Bind prod env vars instead of .env", ["remote"]))
1173
1656
  .option("--include-secrets", "With --env remote: fetch secret values (requires env:secrets:read; audited)")
@@ -1175,7 +1658,7 @@ export function buildProgram() {
1175
1658
  .action(async (pathArg, opts, cmd) => {
1176
1659
  rejectJson(cmd, "dharta dev");
1177
1660
  if (pathArg !== undefined && opts.dir !== undefined) {
1178
- throw new Error("Use either [path] or --dir, not both.");
1661
+ throw new CliUsageError("Use either [path] or --dir, not both.");
1179
1662
  }
1180
1663
  const dir = pathArg !== undefined
1181
1664
  ? normalizeNonBlank(pathArg, "path")
@@ -1185,7 +1668,7 @@ export function buildProgram() {
1185
1668
  if (opts.release !== undefined)
1186
1669
  parseReleaseVersion(opts.release, "--release");
1187
1670
  if (opts.includeSecrets && opts.env !== "remote") {
1188
- throw new Error("--include-secrets requires --env remote.");
1671
+ throw new CliUsageError("--include-secrets requires --env remote.");
1189
1672
  }
1190
1673
  validateAgentSelectorOptions({ agent: opts.agent, project: opts.project });
1191
1674
  await devCmd({
@@ -1193,6 +1676,7 @@ export function buildProgram() {
1193
1676
  message: opts.message,
1194
1677
  user: opts.user,
1195
1678
  verbose: opts.verbose,
1679
+ modelAuth: opts.modelAuth,
1196
1680
  port: opts.port ? parsePort(opts.port) : undefined,
1197
1681
  release: opts.release,
1198
1682
  envRemote: opts.env === "remote",
@@ -1201,6 +1685,7 @@ export function buildProgram() {
1201
1685
  });
1202
1686
  });
1203
1687
  registerArtifactCommands(program);
1688
+ registerGenuiCommands(program);
1204
1689
  const sessionsOpts = (cmd) => cmd
1205
1690
  .option("-a, --agent <slug>", "Agent slug (default: the agent in this folder)")
1206
1691
  .option("-p, --project <slug>", "Alias of --agent")
@@ -1522,9 +2007,8 @@ export function buildProgram() {
1522
2007
  .option("-a, --agent <slug>", "Agent slug (default: the agent in this folder)")
1523
2008
  .option("-p, --project <slug>", "Alias of --agent")
1524
2009
  .option("--dir <dir>", "Directory to resolve the agent from (default: current directory)")
1525
- .addOption(choiceOption("--source <source>", "inherit or platform; omit when using --connector-id", AGENT_MODEL_SOURCES))
1526
- .option("--connector-id <id>", "Numeric BYOK connector id from `dharta model-keys list`; omit --source")
1527
- .option("--model <model>", "Provider model id")
2010
+ .option("--connector <slugs>", "Ordered connection slugs from `dharta models auth list`; use karta for the platform connection or an empty string to inherit")
2011
+ .option("--model-ref <reference>", "Model reference: <model>, connector:<slug>/<model>, or an empty string for the connector default")
1528
2012
  .option("--temperature <number>", "Sampling temperature from 0 to 2")
1529
2013
  .option("--clear-temperature", "Inherit temperature")
1530
2014
  .option("--top-p <number>", "Nucleus sampling probability above 0 and at most 1")
@@ -1597,6 +2081,113 @@ export function buildProgram() {
1597
2081
  else
1598
2082
  console.log(await agentsWorkspaceAccessSet(ctx, resolved, patch));
1599
2083
  });
2084
+ agent
2085
+ .command("rename <name> [slug]")
2086
+ .description("Change an agent's display name; the slug stays as it is.")
2087
+ .option("-a, --agent <slug>", "Agent slug (default: the agent in this folder)")
2088
+ .option("-p, --project <slug>", "Alias of --agent")
2089
+ .option("--dir <dir>", "Agent directory (default: current directory)")
2090
+ .action(async (name, slugArg, _opts, cmd) => {
2091
+ const opts = commandOpts(cmd);
2092
+ const resolvedOpts = await resolveAgentOptions(opts, slugArg);
2093
+ const ctx = await buildContext();
2094
+ const resolved = resolvedOpts.agent;
2095
+ if (isJson(cmd))
2096
+ printJson(await agentsRenameData(ctx, resolved, name));
2097
+ else
2098
+ console.log(await agentsRename(ctx, resolved, name));
2099
+ });
2100
+ agent
2101
+ .command("durable-workspace <state> [slug]")
2102
+ .description(`Enable or disable the durable workspace for an agent's kartas - a cost setting, since durable storage is billed per GB. ${STATE_HELP}`)
2103
+ .option("-a, --agent <slug>", "Agent slug (default: the agent in this folder)")
2104
+ .option("-p, --project <slug>", "Alias of --agent")
2105
+ .option("--dir <dir>", "Agent directory (default: current directory)")
2106
+ .action(async (state, slugArg, _opts, cmd) => {
2107
+ const opts = commandOpts(cmd);
2108
+ const enabled = parseOnOff(state, "state");
2109
+ const resolvedOpts = await resolveAgentOptions(opts, slugArg);
2110
+ const ctx = await buildContext();
2111
+ const resolved = resolvedOpts.agent;
2112
+ if (isJson(cmd))
2113
+ printJson(await agentsDurableWorkspaceSetData(ctx, resolved, enabled));
2114
+ else
2115
+ console.log(await agentsDurableWorkspaceSet(ctx, resolved, enabled));
2116
+ });
2117
+ agent
2118
+ .command("create [name]")
2119
+ .description("Create a hosted agent, or link an installed GitHub repository as its source with --github-repo. `dharta create` scaffolds locally instead.")
2120
+ .option("--slug <slug>", "Agent or source-repo slug (default: derived from the name or repository)")
2121
+ .option("--github-repo <repo>", "Installed GitHub repository to link as the source of truth, by id or owner/name (see `dharta agent github-repos`)")
2122
+ .option("--branch <branch>", "Deploy branch for the linked repository; needs --github-repo")
2123
+ .action(async (name, _opts, cmd) => {
2124
+ const opts = commandOpts(cmd);
2125
+ validateAgentCreateInput(name, opts);
2126
+ const ctx = await buildContext();
2127
+ if (isJson(cmd))
2128
+ printJson(await agentsCreateData(ctx, name, opts));
2129
+ else
2130
+ console.log(await agentsCreate(ctx, name, opts));
2131
+ });
2132
+ agent
2133
+ .command("github-repos")
2134
+ .description("List the GitHub repositories the Dharta App is installed on, with the ids `--github-repo` takes.")
2135
+ .action(async (_opts, cmd) => {
2136
+ const ctx = await buildContext();
2137
+ if (isJson(cmd))
2138
+ printJson(await agentsGithubReposData(ctx));
2139
+ else
2140
+ console.log(await agentsGithubRepos(ctx));
2141
+ });
2142
+ agent
2143
+ .command("create-from-template <template> <name>")
2144
+ .description("Create a hosted agent from a built-in template and publish its first release. `dharta create` scaffolds locally instead.")
2145
+ .option("--slug <slug>", "Agent slug (default: derived from the name)")
2146
+ .option("--description <text>", "Short description")
2147
+ .option("--harness <type>", "Harness slug (default: Dharta's curated default)")
2148
+ .option("--harness-version <version>", "Harness version; needs --harness")
2149
+ .action(async (template, name, _opts, cmd) => {
2150
+ const opts = commandOpts(cmd);
2151
+ validateAgentCreateFromTemplateInput(template, name, opts);
2152
+ const ctx = await buildContext();
2153
+ if (isJson(cmd))
2154
+ printJson(await agentsCreateFromTemplateData(ctx, template, name, opts));
2155
+ else
2156
+ console.log(await agentsCreateFromTemplate(ctx, template, name, opts));
2157
+ });
2158
+ agent
2159
+ .command("redeploy [slug]")
2160
+ .description("Re-sync a GitHub-connected agent and rebuild it from deploy-branch HEAD.")
2161
+ .option("-a, --agent <slug>", "Agent slug (default: the agent in this folder)")
2162
+ .option("-p, --project <slug>", "Alias of --agent")
2163
+ .option("--dir <dir>", "Agent directory (default: current directory)")
2164
+ .action(async (slugArg, _opts, cmd) => {
2165
+ const opts = commandOpts(cmd);
2166
+ const resolvedOpts = await resolveAgentOptions(opts, slugArg);
2167
+ const ctx = await buildContext();
2168
+ const resolved = resolvedOpts.agent;
2169
+ if (isJson(cmd))
2170
+ printJson(await agentsRedeployData(ctx, resolved));
2171
+ else
2172
+ console.log(await agentsRedeploy(ctx, resolved));
2173
+ });
2174
+ agent
2175
+ .command("retry <version> [slug]")
2176
+ .description("Retry a failed browser-created release; it republishes as the next version.")
2177
+ .option("-a, --agent <slug>", "Agent slug (default: the agent in this folder)")
2178
+ .option("-p, --project <slug>", "Alias of --agent")
2179
+ .option("--dir <dir>", "Agent directory (default: current directory)")
2180
+ .action(async (version, slugArg, _opts, cmd) => {
2181
+ const opts = commandOpts(cmd);
2182
+ parseVersion(version);
2183
+ const resolvedOpts = await resolveAgentOptions(opts, slugArg);
2184
+ const ctx = await buildContext();
2185
+ const resolved = resolvedOpts.agent;
2186
+ if (isJson(cmd))
2187
+ printJson(await agentsRetryReleaseData(ctx, resolved, version));
2188
+ else
2189
+ console.log(await agentsRetryRelease(ctx, resolved, version));
2190
+ });
1600
2191
  agent
1601
2192
  .command("delete [slug]")
1602
2193
  .description("Archive an agent.")
@@ -1630,13 +2221,13 @@ export function buildProgram() {
1630
2221
  // owner of target/config resolution and can narrate legacy inference.
1631
2222
  const mode = rawMode ?? (await inferMode(dir));
1632
2223
  if (opts.reconcileSource && mode !== "git") {
1633
- throw new Error("--reconcile-source is only valid for git deploys. " +
2224
+ throw new CliUsageError("--reconcile-source is only valid for git deploys. " +
1634
2225
  "Remove it, or use `--mode git` to reconcile Dharta's hosted source branch.");
1635
2226
  }
1636
2227
  // git mode's output is the live push sideband, not a payload.
1637
2228
  const json = mode === "folder" && isJson(cmd);
1638
2229
  if (mode === "git" && isJson(cmd)) {
1639
- throw new Error("--json is only supported for `dharta deploy --mode folder`; git deploy streams git push output. Run `dharta deploy` without --json or pass `--mode folder`.");
2230
+ throw new CliUsageError("--json is only supported for `dharta deploy --mode folder`; git deploy streams git push output. Run `dharta deploy` without --json or pass `--mode folder`.");
1640
2231
  }
1641
2232
  const ctx = await buildContext();
1642
2233
  const result = await deploy(ctx, slug, {
@@ -1659,7 +2250,7 @@ export function buildProgram() {
1659
2250
  const slug = opts.agent ?? opts.project ?? "";
1660
2251
  if (slug.trim())
1661
2252
  validateAgentSlug(slug, opts.agent !== undefined ? "--agent" : "--project");
1662
- throw new Error("`dharta status` is repo-wide. Use `dharta agent show <slug>` for one remote agent, or `dharta status --dir <path>` for a local repo.");
2253
+ throw new CliUsageError("`dharta status` is repo-wide. Use `dharta agent show <slug>` for one remote agent, or `dharta status --dir <path>` for a local repo.");
1663
2254
  }
1664
2255
  validateAgentSelectorOptions(opts);
1665
2256
  let ctx = null;
@@ -1668,7 +2259,7 @@ export function buildProgram() {
1668
2259
  ctx = await buildContext();
1669
2260
  }
1670
2261
  catch (err) {
1671
- if (!isNotLoggedInError(err))
2262
+ if (!isNotAuthenticatedError(err))
1672
2263
  throw err;
1673
2264
  authMessage = err instanceof Error ? err.message : String(err);
1674
2265
  }
@@ -1728,23 +2319,138 @@ export function buildProgram() {
1728
2319
  // commands and help-only command groups keep a hidden parser option
1729
2320
  // because they reject --json.
1730
2321
  for (const cmd of allCommands(program)) {
2322
+ const jq = new Option("--jq <expr>", "Filter the JSON result through jq (implies --json)");
1731
2323
  if (hidesJsonHelp(cmd)) {
1732
2324
  cmd.addOption(new Option("--json", "Print the result as JSON (machine-readable)").hideHelp());
2325
+ cmd.addOption(jq.hideHelp());
1733
2326
  }
1734
2327
  else {
1735
2328
  cmd.option("--json", jsonHelpDescription(cmd));
2329
+ cmd.addOption(jq);
1736
2330
  }
2331
+ // --profile rides the same mechanic: registered on every node so the flag
2332
+ // parses wherever it appears on the line, read back through
2333
+ // optsWithGlobals(). Hidden on the pure command groups, which only print
2334
+ // help and never resolve a credential.
2335
+ const profile = new Option("--profile <name>", "Profile in ~/.dharta/config.toml to use (env: DHARTA_PROFILE)");
2336
+ if (HELP_ONLY_COMMAND_PATHS.has(commandPath(cmd)) && cmd.parent !== null)
2337
+ profile.hideHelp();
2338
+ cmd.addOption(profile);
2339
+ // --idempotency-key rides the same mechanic for the same reason: it has to
2340
+ // parse wherever it sits on the line, and one flag has to reach every
2341
+ // request the run makes. Hidden on the help-only groups, which issue none.
2342
+ const idempotencyKey = new Option("--idempotency-key <key>", "Send this Idempotency-Key on every request the command makes");
2343
+ if (HELP_ONLY_COMMAND_PATHS.has(commandPath(cmd)) && cmd.parent !== null)
2344
+ idempotencyKey.hideHelp();
2345
+ cmd.addOption(idempotencyKey);
1737
2346
  }
2347
+ // One place decides the active profile for the whole run. preAction hooks are
2348
+ // inherited by every subcommand, so this fires exactly once, before the
2349
+ // action, with the flag resolved from wherever it sat on the command line.
2350
+ program.hook("preAction", async (_thisCommand, actionCommand) => {
2351
+ const opts = actionCommand.optsWithGlobals();
2352
+ setRequestedProfile(opts.profile);
2353
+ rejectNonMutatingIdempotencyKey(actionCommand, opts.idempotencyKey);
2354
+ setRequestedIdempotencyKey(opts.idempotencyKey);
2355
+ resetJsonPayload();
2356
+ // Compile the filter before the action runs, so a typo costs nothing.
2357
+ await armJqFilter(opts.jq);
2358
+ });
2359
+ // The filtered payload is written after the action resolves. postAction runs
2360
+ // for every entry point (parseAsync from the bin, or straight from a test),
2361
+ // and does not run when the action threw - which is right, because a failed
2362
+ // command has no payload to filter.
2363
+ program.hook("postAction", async () => {
2364
+ await flushJsonPayload();
2365
+ });
2366
+ assignTopLevelHelpGroups(program);
1738
2367
  installMissingArgumentChoiceHints(program);
1739
2368
  installTopLevelUnknownCommandGuard(program);
2369
+ installExitOverride(program);
1740
2370
  return program;
1741
2371
  }
1742
- function isNotLoggedInError(err) {
1743
- return err instanceof Error && /^Not logged in\./.test(err.message);
2372
+ // The root help used to carry a hand-written, hand-ordered list of commands in
2373
+ // addHelpText, with commander's own list suppressed - two surfaces to keep in
2374
+ // step, and the list drifted (`files` and `artifact` were never in it).
2375
+ // Commander 15 groups natively, so the groups are declared here, on the tree,
2376
+ // and both `dharta --help` and the generated docs reference read them from it.
2377
+ export const TOP_LEVEL_HELP_GROUPS = [
2378
+ ["Setup and auth", ["login", "auth", "whoami", "create", "setup"]],
2379
+ ["Local and deploy", ["dev", "deploy", "status", "rollback", "logs"]],
2380
+ ["Runtime operations", ["open", "sessions", "session", "ps", "send", "files", "artifact", "schedules"]],
2381
+ ["Agent configuration", ["agent", "env", "appearance", "genui"]],
2382
+ [
2383
+ "Management",
2384
+ [
2385
+ "usage",
2386
+ "analytics",
2387
+ "directories",
2388
+ "fleet",
2389
+ "kartas",
2390
+ "caps",
2391
+ "embed-keys",
2392
+ "webhooks",
2393
+ "audit-log",
2394
+ "keys",
2395
+ "models",
2396
+ "org",
2397
+ "members",
2398
+ "repos",
2399
+ "api",
2400
+ ],
2401
+ ],
2402
+ ["Utilities", ["doctor", "update", "completion"]],
2403
+ ];
2404
+ function assignTopLevelHelpGroups(program) {
2405
+ const order = new Map();
2406
+ for (const [group, names] of TOP_LEVEL_HELP_GROUPS) {
2407
+ for (const name of names) {
2408
+ const cmd = program.commands.find((candidate) => candidate.name() === name);
2409
+ if (!cmd) {
2410
+ throw new Error(`Help group '${group}' names '${name}', which is not a top-level command.`);
2411
+ }
2412
+ cmd.helpGroup(`${group}:`);
2413
+ order.set(name, order.size);
2414
+ }
2415
+ }
2416
+ // Commander discovers group headings in registration order, so the array
2417
+ // itself has to be in group order for the help to read top to bottom.
2418
+ // Ungrouped (hidden) commands keep their place at the end. The array is
2419
+ // typed readonly but is the live list commander renders from, so sorting it
2420
+ // is the ordering hook - there is no public setter.
2421
+ program.commands.sort((a, b) => (order.get(a.name()) ?? Number.MAX_SAFE_INTEGER) - (order.get(b.name()) ?? Number.MAX_SAFE_INTEGER));
2422
+ }
2423
+ // Commander calls process.exit(1) itself for a bad flag, which flattens every
2424
+ // usage mistake into the same code as a failed API call. exitOverride makes it
2425
+ // throw instead, so the single catch in the bin block maps it to EXIT_USAGE.
2426
+ // The setting is per-command, not inherited, so every node gets it.
2427
+ function installExitOverride(program) {
2428
+ for (const cmd of allCommands(program))
2429
+ cmd.exitOverride();
1744
2430
  }
1745
2431
  export async function main(argv) {
1746
2432
  await buildProgram().parseAsync(argv);
1747
2433
  }
2434
+ // The single place a failure turns into an exit status. Returns the code so
2435
+ // the bin block can `process.exit` with it; commander has already printed its
2436
+ // own message, so only CLI-raised errors are narrated here.
2437
+ export function reportCliFailure(err, write = (line) => process.stderr.write(line)) {
2438
+ const code = exitCodeForError(err);
2439
+ if (!isCommanderError(err)) {
2440
+ const msg = err instanceof Error ? err.message : String(err);
2441
+ write(`dharta: ${msg}${retryAdvice(err)}\n`);
2442
+ }
2443
+ return code;
2444
+ }
2445
+ // A rate-limited response carries how long to wait in `Retry-After`, and the
2446
+ // server's own message never repeats it. Without this the user is told they
2447
+ // were throttled and left to guess for how long.
2448
+ function retryAdvice(err) {
2449
+ const seconds = err?.retryAfterSeconds;
2450
+ if (typeof seconds !== "number" || !Number.isFinite(seconds) || seconds < 0)
2451
+ return "";
2452
+ return ` Retry after ${seconds} seconds.`;
2453
+ }
1748
2454
  function allCommands(root) {
1749
2455
  const out = [];
1750
2456
  const visit = (cmd) => {
@@ -1761,8 +2467,11 @@ function hidesJsonHelp(cmd) {
1761
2467
  "dharta auth",
1762
2468
  "dharta analytics",
1763
2469
  "dharta keys",
1764
- "dharta model-keys",
2470
+ "dharta models",
2471
+ "dharta models auth",
2472
+ "dharta org",
1765
2473
  "dharta members",
2474
+ "dharta repos",
1766
2475
  "dharta embed-keys",
1767
2476
  "dharta caps",
1768
2477
  "dharta appearance",
@@ -1771,6 +2480,7 @@ function hidesJsonHelp(cmd) {
1771
2480
  "dharta webhooks",
1772
2481
  "dharta env",
1773
2482
  "dharta agent",
2483
+ "dharta genui",
1774
2484
  "dharta git-credential",
1775
2485
  "dharta dev",
1776
2486
  "dharta logs",
@@ -1800,8 +2510,11 @@ const HELP_ONLY_COMMAND_PATHS = new Set([
1800
2510
  "dharta auth",
1801
2511
  "dharta analytics",
1802
2512
  "dharta keys",
1803
- "dharta model-keys",
2513
+ "dharta models",
2514
+ "dharta models auth",
2515
+ "dharta org",
1804
2516
  "dharta members",
2517
+ "dharta repos",
1805
2518
  "dharta embed-keys",
1806
2519
  "dharta caps",
1807
2520
  "dharta caps budget",
@@ -1811,6 +2524,7 @@ const HELP_ONLY_COMMAND_PATHS = new Set([
1811
2524
  "dharta webhooks",
1812
2525
  "dharta env",
1813
2526
  "dharta agent",
2527
+ "dharta genui",
1814
2528
  ]);
1815
2529
  function rejectUnknownTopLevelCommand(program, argv, options) {
1816
2530
  const args = argv ? [...argv].slice(options?.from === "user" ? 0 : 2) : process.argv.slice(2);
@@ -1830,8 +2544,7 @@ function rejectUnknownTopLevelCommand(program, argv, options) {
1830
2544
  const path = commandPath(cursor);
1831
2545
  if (!HELP_ONLY_COMMAND_PATHS.has(path))
1832
2546
  return;
1833
- const visible = cursor.commands.filter((cmd) => !cmd._hidden);
1834
- const child = visible.find((cmd) => cmd.name() === token || cmd.aliases().includes(token));
2547
+ const child = visibleSubcommands(cursor).find((cmd) => cmd.name() === token || cmd.aliases().includes(token));
1835
2548
  if (child) {
1836
2549
  cursor = child;
1837
2550
  continue;
@@ -1907,21 +2620,21 @@ function parseOnOff(value, name) {
1907
2620
  if (["off", "false", "disabled", "disable", "pause", "paused"].includes(normalized))
1908
2621
  return false;
1909
2622
  const suggestion = closestChoice(normalized, ["on", "off", "enabled", "disabled", "true", "false"]);
1910
- throw new Error(`${name} must be on/off, enabled/disabled, or true/false.` +
2623
+ throw new CliUsageError(`${name} must be on/off, enabled/disabled, or true/false.` +
1911
2624
  (suggestion ? ` Did you mean ${suggestion}?` : ""));
1912
2625
  }
1913
2626
  export async function readStdin() {
1914
2627
  if (process.stdin.isTTY) {
1915
2628
  // Reading a TTY would block silently until Ctrl-D — fail with the
1916
2629
  // usage instead (gh parity: --with-token requires piped input).
1917
- throw new Error("No piped input. Usage: echo $DHARTA_API_KEY | dharta login --with-token");
2630
+ throw new CliUsageError("No piped input. Usage: echo $DHARTA_API_KEY | dharta login --with-token");
1918
2631
  }
1919
2632
  const chunks = [];
1920
2633
  for await (const chunk of process.stdin)
1921
2634
  chunks.push(Buffer.from(chunk));
1922
2635
  const token = Buffer.concat(chunks).toString("utf8").trim();
1923
2636
  if (!token) {
1924
- throw new Error("No token on stdin. Usage: echo $DHARTA_API_KEY | dharta login --with-token");
2637
+ throw new CliUsageError("No token on stdin. Usage: echo $DHARTA_API_KEY | dharta login --with-token");
1925
2638
  }
1926
2639
  return token;
1927
2640
  }
@@ -1931,25 +2644,25 @@ function parseVersion(input) {
1931
2644
  return parseReleaseVersion(input, "version");
1932
2645
  }
1933
2646
  catch {
1934
- throw new Error(`Invalid version: ${input.trim()}. Use e.g. v3 or 3.`);
2647
+ throw new CliUsageError(`Invalid version: ${input.trim()}. Use e.g. v3 or 3.`);
1935
2648
  }
1936
2649
  }
1937
2650
  function parseRollbackTarget(input) {
1938
2651
  if (input === undefined) {
1939
- throw new Error("Pass --to <version>. Usage: dharta rollback [slug] --to v3");
2652
+ throw new CliUsageError("Pass --to <version>. Usage: dharta rollback [slug] --to v3");
1940
2653
  }
1941
2654
  return parseVersion(input);
1942
2655
  }
1943
2656
  function parsePort(input) {
1944
2657
  const normalized = input.trim();
1945
2658
  if (!normalized)
1946
- throw new Error("--port cannot be blank.");
2659
+ throw new CliUsageError("--port cannot be blank.");
1947
2660
  if (!/^[1-9]\d*$/.test(normalized)) {
1948
- throw new Error(`--port must be an integer between 1 and 65535.`);
2661
+ throw new CliUsageError(`--port must be an integer between 1 and 65535.`);
1949
2662
  }
1950
2663
  const port = Number(normalized);
1951
2664
  if (port > 65535) {
1952
- throw new Error(`--port must be an integer between 1 and 65535.`);
2665
+ throw new CliUsageError(`--port must be an integer between 1 and 65535.`);
1953
2666
  }
1954
2667
  return port;
1955
2668
  }
@@ -1970,9 +2683,7 @@ const invokedAsBin = (() => {
1970
2683
  })();
1971
2684
  if (invokedAsBin) {
1972
2685
  main(process.argv).catch((err) => {
1973
- const msg = err instanceof Error ? err.message : String(err);
1974
- process.stderr.write(`dharta: ${msg}\n`);
1975
- process.exit(1);
2686
+ process.exit(reportCliFailure(err));
1976
2687
  });
1977
2688
  }
1978
2689
  //# sourceMappingURL=cli.js.map