aui-agent-builder 0.4.0-alpha.0 → 0.4.0

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 (314) hide show
  1. package/LICENSE +1 -2
  2. package/README.md +608 -114
  3. package/dist/api-client/apollo-client.d.ts +427 -0
  4. package/dist/api-client/apollo-client.d.ts.map +1 -0
  5. package/dist/api-client/apollo-client.js +347 -0
  6. package/dist/api-client/apollo-client.js.map +1 -0
  7. package/dist/api-client/index.d.ts +541 -21
  8. package/dist/api-client/index.d.ts.map +1 -1
  9. package/dist/api-client/index.js +956 -50
  10. package/dist/api-client/index.js.map +1 -1
  11. package/dist/api-client/kb-view-client.d.ts +94 -19
  12. package/dist/api-client/kb-view-client.d.ts.map +1 -1
  13. package/dist/api-client/kb-view-client.js +332 -35
  14. package/dist/api-client/kb-view-client.js.map +1 -1
  15. package/dist/api-client/rag-client.d.ts +28 -60
  16. package/dist/api-client/rag-client.d.ts.map +1 -1
  17. package/dist/api-client/rag-client.js +46 -42
  18. package/dist/api-client/rag-client.js.map +1 -1
  19. package/dist/commands/account.d.ts +11 -4
  20. package/dist/commands/account.d.ts.map +1 -1
  21. package/dist/commands/account.js +76 -59
  22. package/dist/commands/account.js.map +1 -1
  23. package/dist/commands/agents.d.ts +66 -2
  24. package/dist/commands/agents.d.ts.map +1 -1
  25. package/dist/commands/agents.js +706 -92
  26. package/dist/commands/agents.js.map +1 -1
  27. package/dist/commands/apollo.d.ts +185 -0
  28. package/dist/commands/apollo.d.ts.map +1 -0
  29. package/dist/commands/apollo.js +682 -0
  30. package/dist/commands/apollo.js.map +1 -0
  31. package/dist/commands/env.js +1 -1
  32. package/dist/commands/env.js.map +1 -1
  33. package/dist/commands/import-agent.d.ts +31 -0
  34. package/dist/commands/import-agent.d.ts.map +1 -1
  35. package/dist/commands/import-agent.js +1068 -283
  36. package/dist/commands/import-agent.js.map +1 -1
  37. package/dist/commands/index.d.ts +3 -3
  38. package/dist/commands/index.d.ts.map +1 -1
  39. package/dist/commands/index.js +3 -3
  40. package/dist/commands/index.js.map +1 -1
  41. package/dist/commands/init.d.ts.map +1 -1
  42. package/dist/commands/init.js +403 -94
  43. package/dist/commands/init.js.map +1 -1
  44. package/dist/commands/integration-mcp-test.d.ts +68 -0
  45. package/dist/commands/integration-mcp-test.d.ts.map +1 -0
  46. package/dist/commands/integration-mcp-test.js +885 -0
  47. package/dist/commands/integration-mcp-test.js.map +1 -0
  48. package/dist/commands/integration-mcp-url.d.ts +40 -0
  49. package/dist/commands/integration-mcp-url.d.ts.map +1 -0
  50. package/dist/commands/integration-mcp-url.js +162 -0
  51. package/dist/commands/integration-mcp-url.js.map +1 -0
  52. package/dist/commands/integration-test.d.ts +108 -0
  53. package/dist/commands/integration-test.d.ts.map +1 -0
  54. package/dist/commands/integration-test.js +251 -0
  55. package/dist/commands/integration-test.js.map +1 -0
  56. package/dist/commands/integration-toolkits.d.ts +35 -0
  57. package/dist/commands/integration-toolkits.d.ts.map +1 -0
  58. package/dist/commands/integration-toolkits.js +101 -0
  59. package/dist/commands/integration-toolkits.js.map +1 -0
  60. package/dist/commands/integration-tools.d.ts +34 -0
  61. package/dist/commands/integration-tools.d.ts.map +1 -0
  62. package/dist/commands/integration-tools.js +108 -0
  63. package/dist/commands/integration-tools.js.map +1 -0
  64. package/dist/commands/integration.d.ts +83 -9
  65. package/dist/commands/integration.d.ts.map +1 -1
  66. package/dist/commands/integration.js +700 -252
  67. package/dist/commands/integration.js.map +1 -1
  68. package/dist/commands/legacy/push-records-mode.d.ts +166 -0
  69. package/dist/commands/legacy/push-records-mode.d.ts.map +1 -0
  70. package/dist/commands/legacy/push-records-mode.js +2621 -0
  71. package/dist/commands/legacy/push-records-mode.js.map +1 -0
  72. package/dist/commands/login.d.ts.map +1 -1
  73. package/dist/commands/login.js +34 -5
  74. package/dist/commands/login.js.map +1 -1
  75. package/dist/commands/pull-agent.d.ts +10 -0
  76. package/dist/commands/pull-agent.d.ts.map +1 -1
  77. package/dist/commands/pull-agent.js +713 -178
  78. package/dist/commands/pull-agent.js.map +1 -1
  79. package/dist/commands/push.d.ts +91 -6
  80. package/dist/commands/push.d.ts.map +1 -1
  81. package/dist/commands/push.js +1514 -1144
  82. package/dist/commands/push.js.map +1 -1
  83. package/dist/commands/rag.d.ts +1 -0
  84. package/dist/commands/rag.d.ts.map +1 -1
  85. package/dist/commands/rag.js +92 -36
  86. package/dist/commands/rag.js.map +1 -1
  87. package/dist/commands/report.d.ts +138 -0
  88. package/dist/commands/report.d.ts.map +1 -0
  89. package/dist/commands/report.js +205 -0
  90. package/dist/commands/report.js.map +1 -0
  91. package/dist/commands/serve.d.ts.map +1 -1
  92. package/dist/commands/serve.js +1 -4
  93. package/dist/commands/serve.js.map +1 -1
  94. package/dist/commands/sync-session.d.ts +13 -0
  95. package/dist/commands/sync-session.d.ts.map +1 -0
  96. package/dist/commands/sync-session.js +56 -0
  97. package/dist/commands/sync-session.js.map +1 -0
  98. package/dist/commands/upgrade.d.ts.map +1 -1
  99. package/dist/commands/upgrade.js +1 -1
  100. package/dist/commands/upgrade.js.map +1 -1
  101. package/dist/commands/util/agent-mode.d.ts +69 -0
  102. package/dist/commands/util/agent-mode.d.ts.map +1 -0
  103. package/dist/commands/util/agent-mode.js +159 -0
  104. package/dist/commands/util/agent-mode.js.map +1 -0
  105. package/dist/commands/util/agent-resolve.d.ts +102 -0
  106. package/dist/commands/util/agent-resolve.d.ts.map +1 -0
  107. package/dist/commands/util/agent-resolve.js +148 -0
  108. package/dist/commands/util/agent-resolve.js.map +1 -0
  109. package/dist/commands/util/apollo-agent.d.ts +70 -0
  110. package/dist/commands/util/apollo-agent.d.ts.map +1 -0
  111. package/dist/commands/util/apollo-agent.js +100 -0
  112. package/dist/commands/util/apollo-agent.js.map +1 -0
  113. package/dist/commands/validate.d.ts +129 -9
  114. package/dist/commands/validate.d.ts.map +1 -1
  115. package/dist/commands/validate.js +666 -804
  116. package/dist/commands/validate.js.map +1 -1
  117. package/dist/commands/version-snapshot.d.ts +21 -0
  118. package/dist/commands/version-snapshot.d.ts.map +1 -0
  119. package/dist/commands/version-snapshot.js +948 -0
  120. package/dist/commands/version-snapshot.js.map +1 -0
  121. package/dist/commands/version.d.ts +15 -2
  122. package/dist/commands/version.d.ts.map +1 -1
  123. package/dist/commands/version.js +439 -206
  124. package/dist/commands/version.js.map +1 -1
  125. package/dist/config/index.d.ts +96 -5
  126. package/dist/config/index.d.ts.map +1 -1
  127. package/dist/config/index.js +97 -59
  128. package/dist/config/index.js.map +1 -1
  129. package/dist/errors/index.d.ts +1 -12
  130. package/dist/errors/index.d.ts.map +1 -1
  131. package/dist/errors/index.js +90 -8
  132. package/dist/errors/index.js.map +1 -1
  133. package/dist/index.d.ts +2 -1
  134. package/dist/index.d.ts.map +1 -1
  135. package/dist/index.js +1066 -174
  136. package/dist/index.js.map +1 -1
  137. package/dist/services/account.service.js +1 -1
  138. package/dist/services/account.service.js.map +1 -1
  139. package/dist/services/agents.service.d.ts.map +1 -1
  140. package/dist/services/agents.service.js +11 -5
  141. package/dist/services/agents.service.js.map +1 -1
  142. package/dist/services/auth.service.d.ts +78 -0
  143. package/dist/services/auth.service.d.ts.map +1 -1
  144. package/dist/services/auth.service.js +290 -16
  145. package/dist/services/auth.service.js.map +1 -1
  146. package/dist/services/integration.service.d.ts +374 -22
  147. package/dist/services/integration.service.d.ts.map +1 -1
  148. package/dist/services/integration.service.js +643 -95
  149. package/dist/services/integration.service.js.map +1 -1
  150. package/dist/services/kb-view.service.d.ts +17 -30
  151. package/dist/services/kb-view.service.d.ts.map +1 -1
  152. package/dist/services/kb-view.service.js +191 -118
  153. package/dist/services/kb-view.service.js.map +1 -1
  154. package/dist/services/list-agents.service.d.ts +10 -0
  155. package/dist/services/list-agents.service.d.ts.map +1 -1
  156. package/dist/services/list-agents.service.js +16 -21
  157. package/dist/services/list-agents.service.js.map +1 -1
  158. package/dist/services/pull-schema.service.d.ts +20 -1
  159. package/dist/services/pull-schema.service.d.ts.map +1 -1
  160. package/dist/services/pull-schema.service.js +313 -121
  161. package/dist/services/pull-schema.service.js.map +1 -1
  162. package/dist/services/rag.service.d.ts +21 -8
  163. package/dist/services/rag.service.d.ts.map +1 -1
  164. package/dist/services/rag.service.js +43 -16
  165. package/dist/services/rag.service.js.map +1 -1
  166. package/dist/services/status.service.d.ts +8 -0
  167. package/dist/services/status.service.d.ts.map +1 -1
  168. package/dist/services/status.service.js +16 -1
  169. package/dist/services/status.service.js.map +1 -1
  170. package/dist/services/sync-session.service.d.ts +38 -0
  171. package/dist/services/sync-session.service.d.ts.map +1 -0
  172. package/dist/services/sync-session.service.js +93 -0
  173. package/dist/services/sync-session.service.js.map +1 -0
  174. package/dist/telemetry.d.ts +169 -2
  175. package/dist/telemetry.d.ts.map +1 -1
  176. package/dist/telemetry.js +878 -4
  177. package/dist/telemetry.js.map +1 -1
  178. package/dist/types/entity.d.ts +21 -0
  179. package/dist/types/entity.d.ts.map +1 -1
  180. package/dist/ui/components/Banner.js +1 -1
  181. package/dist/ui/components/Banner.js.map +1 -1
  182. package/dist/ui/components/EnvironmentBadge.d.ts +8 -0
  183. package/dist/ui/components/EnvironmentBadge.d.ts.map +1 -0
  184. package/dist/ui/components/EnvironmentBadge.js +11 -0
  185. package/dist/ui/components/EnvironmentBadge.js.map +1 -0
  186. package/dist/ui/components/index.d.ts +1 -0
  187. package/dist/ui/components/index.d.ts.map +1 -1
  188. package/dist/ui/components/index.js +1 -0
  189. package/dist/ui/components/index.js.map +1 -1
  190. package/dist/ui/theme.d.ts +13 -0
  191. package/dist/ui/theme.d.ts.map +1 -1
  192. package/dist/ui/theme.js +12 -0
  193. package/dist/ui/theme.js.map +1 -1
  194. package/dist/ui/views/AccountView.js +1 -1
  195. package/dist/ui/views/AccountView.js.map +1 -1
  196. package/dist/ui/views/EnvView.d.ts.map +1 -1
  197. package/dist/ui/views/EnvView.js +2 -2
  198. package/dist/ui/views/EnvView.js.map +1 -1
  199. package/dist/ui/views/ImportAgentView.d.ts +15 -0
  200. package/dist/ui/views/ImportAgentView.d.ts.map +1 -1
  201. package/dist/ui/views/ImportAgentView.js +8 -3
  202. package/dist/ui/views/ImportAgentView.js.map +1 -1
  203. package/dist/ui/views/IntegrationView.d.ts +3 -1
  204. package/dist/ui/views/IntegrationView.d.ts.map +1 -1
  205. package/dist/ui/views/IntegrationView.js +2 -2
  206. package/dist/ui/views/IntegrationView.js.map +1 -1
  207. package/dist/ui/views/LoginView.d.ts +2 -1
  208. package/dist/ui/views/LoginView.d.ts.map +1 -1
  209. package/dist/ui/views/LoginView.js +20 -14
  210. package/dist/ui/views/LoginView.js.map +1 -1
  211. package/dist/ui/views/PushView.d.ts +3 -1
  212. package/dist/ui/views/PushView.d.ts.map +1 -1
  213. package/dist/ui/views/PushView.js +8 -2
  214. package/dist/ui/views/PushView.js.map +1 -1
  215. package/dist/ui/views/RagView.d.ts +6 -1
  216. package/dist/ui/views/RagView.d.ts.map +1 -1
  217. package/dist/ui/views/RagView.js +23 -0
  218. package/dist/ui/views/RagView.js.map +1 -1
  219. package/dist/ui/views/StatusView.js +4 -4
  220. package/dist/ui/views/StatusView.js.map +1 -1
  221. package/dist/ui/views/SyncSessionView.d.ts +7 -0
  222. package/dist/ui/views/SyncSessionView.d.ts.map +1 -0
  223. package/dist/ui/views/SyncSessionView.js +10 -0
  224. package/dist/ui/views/SyncSessionView.js.map +1 -0
  225. package/dist/utils/agent-injection.d.ts +49 -0
  226. package/dist/utils/agent-injection.d.ts.map +1 -0
  227. package/dist/utils/agent-injection.js +83 -0
  228. package/dist/utils/agent-injection.js.map +1 -0
  229. package/dist/utils/fetch-with-timeout.d.ts +57 -0
  230. package/dist/utils/fetch-with-timeout.d.ts.map +1 -0
  231. package/dist/utils/fetch-with-timeout.js +125 -0
  232. package/dist/utils/fetch-with-timeout.js.map +1 -0
  233. package/dist/utils/help-json.d.ts +44 -0
  234. package/dist/utils/help-json.d.ts.map +1 -0
  235. package/dist/utils/help-json.js +62 -0
  236. package/dist/utils/help-json.js.map +1 -0
  237. package/dist/utils/index.d.ts +82 -18
  238. package/dist/utils/index.d.ts.map +1 -1
  239. package/dist/utils/index.js +387 -80
  240. package/dist/utils/index.js.map +1 -1
  241. package/dist/utils/json-output.d.ts +10 -0
  242. package/dist/utils/json-output.d.ts.map +1 -1
  243. package/dist/utils/json-output.js +14 -0
  244. package/dist/utils/json-output.js.map +1 -1
  245. package/dist/utils/payload-store.d.ts +40 -0
  246. package/dist/utils/payload-store.d.ts.map +1 -0
  247. package/dist/utils/payload-store.js +82 -0
  248. package/dist/utils/payload-store.js.map +1 -0
  249. package/dist/utils/request-capture.d.ts +26 -0
  250. package/dist/utils/request-capture.d.ts.map +1 -1
  251. package/dist/utils/request-capture.js +67 -0
  252. package/dist/utils/request-capture.js.map +1 -1
  253. package/dist/utils/select-prompt.d.ts +32 -0
  254. package/dist/utils/select-prompt.d.ts.map +1 -0
  255. package/dist/utils/select-prompt.js +71 -0
  256. package/dist/utils/select-prompt.js.map +1 -0
  257. package/dist/utils/update-notifier.d.ts.map +1 -1
  258. package/dist/utils/update-notifier.js +30 -3
  259. package/dist/utils/update-notifier.js.map +1 -1
  260. package/dist/web/assets/{index-DSg2xrPw.js → index-n4de71HW.js} +1 -1
  261. package/dist/web/index.html +1 -1
  262. package/package.json +10 -6
  263. package/dist/commands/add-integration.d.ts +0 -20
  264. package/dist/commands/add-integration.d.ts.map +0 -1
  265. package/dist/commands/add-integration.js +0 -385
  266. package/dist/commands/add-integration.js.map +0 -1
  267. package/dist/commands/add-tool.d.ts +0 -17
  268. package/dist/commands/add-tool.d.ts.map +0 -1
  269. package/dist/commands/add-tool.js +0 -225
  270. package/dist/commands/add-tool.js.map +0 -1
  271. package/dist/commands/chat.d.ts +0 -20
  272. package/dist/commands/chat.d.ts.map +0 -1
  273. package/dist/commands/chat.js +0 -545
  274. package/dist/commands/chat.js.map +0 -1
  275. package/dist/commands/create-agent.d.ts +0 -17
  276. package/dist/commands/create-agent.d.ts.map +0 -1
  277. package/dist/commands/create-agent.js +0 -18
  278. package/dist/commands/create-agent.js.map +0 -1
  279. package/dist/commands/lsp.d.ts +0 -13
  280. package/dist/commands/lsp.d.ts.map +0 -1
  281. package/dist/commands/lsp.js +0 -17
  282. package/dist/commands/lsp.js.map +0 -1
  283. package/dist/commands/widget.d.ts +0 -18
  284. package/dist/commands/widget.d.ts.map +0 -1
  285. package/dist/commands/widget.js +0 -153
  286. package/dist/commands/widget.js.map +0 -1
  287. package/dist/lsp/cross-refs.d.ts +0 -53
  288. package/dist/lsp/cross-refs.d.ts.map +0 -1
  289. package/dist/lsp/cross-refs.js +0 -330
  290. package/dist/lsp/cross-refs.js.map +0 -1
  291. package/dist/lsp/cross-refs.test.d.ts +0 -2
  292. package/dist/lsp/cross-refs.test.d.ts.map +0 -1
  293. package/dist/lsp/cross-refs.test.js +0 -130
  294. package/dist/lsp/cross-refs.test.js.map +0 -1
  295. package/dist/lsp/schemas.d.ts +0 -57
  296. package/dist/lsp/schemas.d.ts.map +0 -1
  297. package/dist/lsp/schemas.js +0 -126
  298. package/dist/lsp/schemas.js.map +0 -1
  299. package/dist/lsp/schemas.test.d.ts +0 -2
  300. package/dist/lsp/schemas.test.d.ts.map +0 -1
  301. package/dist/lsp/schemas.test.js +0 -74
  302. package/dist/lsp/schemas.test.js.map +0 -1
  303. package/dist/lsp/server.d.ts +0 -11
  304. package/dist/lsp/server.d.ts.map +0 -1
  305. package/dist/lsp/server.js +0 -205
  306. package/dist/lsp/server.js.map +0 -1
  307. package/dist/ui/views/ChatView.d.ts +0 -26
  308. package/dist/ui/views/ChatView.d.ts.map +0 -1
  309. package/dist/ui/views/ChatView.js +0 -96
  310. package/dist/ui/views/ChatView.js.map +0 -1
  311. package/dist/ui/views/__tests__/StatusView.test.d.ts +0 -2
  312. package/dist/ui/views/__tests__/StatusView.test.d.ts.map +0 -1
  313. package/dist/ui/views/__tests__/StatusView.test.js +0 -158
  314. package/dist/ui/views/__tests__/StatusView.test.js.map +0 -1
@@ -2,11 +2,12 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { render } from "ink";
3
3
  import { Box, Text } from "ink";
4
4
  import inquirer from "inquirer";
5
- import chalk from "chalk";
6
- import { getConfig, loadSession, loadProjectConfig, findProjectRoot, } from "../config/index.js";
5
+ import { getConfig, loadSession, loadProjectConfig, saveProjectConfig, findProjectRoot, } from "../config/index.js";
7
6
  import { AUIClient } from "../api-client/index.js";
8
- import { AuthenticationError } from "../errors/index.js";
9
- import { isJsonMode, outputJson, outputJsonError, stderrLog } from "../utils/json-output.js";
7
+ import { AuthenticationError, CLIError } from "../errors/index.js";
8
+ import { isJsonMode, isInteractiveSession, outputJson, outputJsonError, stderrLog, } from "../utils/json-output.js";
9
+ import { resolveAgentManagementInfo } from "./util/agent-resolve.js";
10
+ import { detectAgentBundleMode } from "./util/agent-mode.js";
10
11
  import { Header, StatusLine, Spinner, ErrorDisplay, Divider, KeyValueGroup, } from "../ui/components/index.js";
11
12
  import { colors } from "../ui/theme.js";
12
13
  import { loadAgentSettingsApiKey } from "../config/index.js";
@@ -37,7 +38,7 @@ function startSpinner(label) {
37
38
  }
38
39
  // ─── Helpers ───
39
40
  function vLabel(v) {
40
- return `v${v.version_number}.${v.version_revision_number}`;
41
+ return `v${v.version_number}`;
41
42
  }
42
43
  function statusColor(status) {
43
44
  if (status === "published")
@@ -49,6 +50,28 @@ function statusColor(status) {
49
50
  function statsLabel(stats) {
50
51
  return `total:${stats.total ?? "?"} W:${stats.workflows} P:${stats.policies} I:${stats.integrations ?? 0} Pr:${stats.parameters ?? 0}`;
51
52
  }
53
+ /**
54
+ * Does the resolved agent correspond to the agent this project's `.auirc`
55
+ * already tracks? Used to decide whether `version create` may repoint the
56
+ * `.auirc` at the freshly created draft. When no explicit `--agent-id` is
57
+ * passed the agent is resolved FROM the `.auirc`, so it matches by
58
+ * construction; this guard only matters when `--agent-id` targets a
59
+ * different agent than the project folder is checked out for. A `.auirc`
60
+ * with no agent identifiers at all is treated as a match (nothing to
61
+ * conflict with).
62
+ */
63
+ function agentMatchesProject(agent, projectConfig) {
64
+ if (!projectConfig.agent_management_id && !projectConfig.agent_id)
65
+ return true;
66
+ if (projectConfig.agent_management_id &&
67
+ projectConfig.agent_management_id === agent.id)
68
+ return true;
69
+ if (projectConfig.agent_id &&
70
+ (projectConfig.agent_id === agent.scope?.network_id ||
71
+ projectConfig.agent_id === agent.id))
72
+ return true;
73
+ return false;
74
+ }
52
75
  function getAuthenticatedClient() {
53
76
  const config = getConfig();
54
77
  if (!config.isAuthenticated) {
@@ -72,32 +95,41 @@ async function resolveAgentId(client, agentIdArg) {
72
95
  return client.agentManagement.getAgent(agentIdArg);
73
96
  }
74
97
  const session = loadSession();
75
- // Try direct lookup by agent_management_id from session
76
- if (session.agent_management_id) {
77
- try {
78
- return await client.agentManagement.getAgent(session.agent_management_id);
79
- }
80
- catch {
81
- // ID might be stale, fall through
82
- }
83
- }
84
- // Check project config (.auirc) — if we're inside an imported project,
85
- // use its agent_id to find the agent-management record
98
+ // Project config (.auirc) takes priority over session — if you're inside a
99
+ // project, that's the agent you mean. Resolve from the PROJECT's own ids
100
+ // (preferring `agent_management_id`, the canonical agent-management UUID,
101
+ // exactly like `aui push`). Crucially, if the project's ids don't resolve
102
+ // we throw a clear error instead of silently falling through to the
103
+ // session's "current" agent — that silent fallthrough is what caused
104
+ // `version create` to write drafts on the wrong agent and to repoint a
105
+ // foreign `.auirc` at them.
86
106
  const projectRoot = findProjectRoot();
87
107
  if (projectRoot) {
88
108
  const projectConfig = loadProjectConfig(projectRoot);
89
- if (projectConfig?.agent_id) {
90
- try {
91
- const resp = await client.agentManagement.listAgents(client.getOrganizationId(), 1, 50, { network_id: projectConfig.agent_id });
92
- const match = resp.items.find((a) => a.scope.network_id === projectConfig.agent_id || a.id === projectConfig.agent_id);
93
- if (match)
94
- return match;
95
- }
96
- catch {
97
- // listing failed
98
- }
109
+ if (projectConfig?.agent_management_id || projectConfig?.agent_id) {
110
+ const { agentInfo, errors } = await resolveAgentManagementInfo(client, {
111
+ projectAgentManagementId: projectConfig.agent_management_id,
112
+ projectNetworkId: projectConfig.agent_id,
113
+ });
114
+ if (agentInfo)
115
+ return agentInfo;
116
+ throw new CLIError("Could not resolve the agent for this project (.auirc).", {
117
+ code: "API_CLIENT_ERROR",
118
+ suggestion: "Pass --agent-id <agentManagementId> explicitly, or re-run `aui import` / `aui pull` to refresh .auirc." +
119
+ (errors.length ? ` Attempts: ${errors.join("; ")}` : ""),
120
+ });
99
121
  }
100
122
  }
123
+ // No project context (.auirc): fall back to the session's agent. Same
124
+ // shared resolver, session inputs only.
125
+ {
126
+ const { agentInfo } = await resolveAgentManagementInfo(client, {
127
+ sessionAgentManagementId: session.agent_management_id,
128
+ sessionNetworkId: session.network_id,
129
+ });
130
+ if (agentInfo)
131
+ return agentInfo;
132
+ }
101
133
  const allAgents = [];
102
134
  let page = 1;
103
135
  let hasMore = true;
@@ -154,6 +186,15 @@ async function resolveAgentId(client, agentIdArg) {
154
186
  if (allAgents.length === 1) {
155
187
  return allAgents[0];
156
188
  }
189
+ // Multiple candidates and nothing pinned by project/session. Only an
190
+ // interactive TTY can disambiguate — a non-TTY caller (Claude Code,
191
+ // sandbox, pipe) must pass --agent-id rather than hang on the picker.
192
+ if (!isInteractiveSession()) {
193
+ throw new CLIError("Multiple agents found and none is selected for this context.", {
194
+ code: "API_CLIENT_ERROR",
195
+ suggestion: "Pass --agent-id <agentManagementId> to choose one, or run `aui agents --switch` in an interactive terminal first.",
196
+ });
197
+ }
157
198
  const { selected } = await inquirer.prompt([
158
199
  {
159
200
  type: "list",
@@ -168,6 +209,97 @@ async function resolveAgentId(client, agentIdArg) {
168
209
  ]);
169
210
  return selected;
170
211
  }
212
+ /**
213
+ * STRICT agent resolver for the mutating version ops (publish / activate /
214
+ * archive). Unlike `resolveAgentId`, it NEVER falls back to the session and
215
+ * NEVER prompts — the agent comes from an explicit `--agent-id` or the
216
+ * project's `.auirc`, and nothing else. Run outside an agent directory with no
217
+ * `--agent-id`, it throws so the command can say "you're not in an agent
218
+ * directory" instead of silently mutating whatever the session last pointed
219
+ * at. This is the safety guarantee behind CLI-4: publish/activate/archive can
220
+ * only ever touch the agent the current folder tracks (or one you name).
221
+ *
222
+ * `--agent-id` is resolved network-id-tolerantly: the value is passed as BOTH
223
+ * the management id and the network id, so an id that is actually a network id
224
+ * still resolves to the canonical agent-management record. The same OR'd
225
+ * lookup covers the mis-synced `.auirc` case where `agent_id` holds a network
226
+ * id rather than the management id.
227
+ */
228
+ async function resolveStrictAgent(client, agentIdArg) {
229
+ if (agentIdArg) {
230
+ const { agentInfo, errors } = await resolveAgentManagementInfo(client, {
231
+ projectAgentManagementId: agentIdArg,
232
+ projectNetworkId: agentIdArg,
233
+ });
234
+ if (agentInfo)
235
+ return agentInfo;
236
+ throw new CLIError(`Could not resolve --agent-id ${agentIdArg}.`, {
237
+ code: "API_CLIENT_ERROR",
238
+ suggestion: "Pass a valid agent-management id or network id." +
239
+ (errors.length ? ` Attempts: ${errors.join("; ")}` : ""),
240
+ });
241
+ }
242
+ const projectRoot = findProjectRoot();
243
+ const projectConfig = projectRoot ? loadProjectConfig(projectRoot) : null;
244
+ if (!projectRoot ||
245
+ !projectConfig ||
246
+ (!projectConfig.agent_management_id && !projectConfig.agent_id)) {
247
+ throw new CLIError("Not in an agent directory (no .auirc tracking an agent).", {
248
+ code: "API_CLIENT_ERROR",
249
+ suggestion: "cd into the agent's project folder, or pass --agent-id <id> together with the version id explicitly.",
250
+ });
251
+ }
252
+ const { agentInfo, errors } = await resolveAgentManagementInfo(client, {
253
+ projectAgentManagementId: projectConfig.agent_management_id,
254
+ projectNetworkId: projectConfig.agent_id,
255
+ });
256
+ if (agentInfo)
257
+ return agentInfo;
258
+ throw new CLIError("Could not resolve the agent for this project (.auirc).", {
259
+ code: "API_CLIENT_ERROR",
260
+ suggestion: "Pass --agent-id <agentManagementId> explicitly, or re-run `aui import` / `aui pull` to refresh .auirc." +
261
+ (errors.length ? ` Attempts: ${errors.join("; ")}` : ""),
262
+ });
263
+ }
264
+ /**
265
+ * Resolve the version a mutating op targets. Precedence: explicit
266
+ * `versionIdArg` → the `version_id` tracked in this project's `.auirc`. There
267
+ * is NO interactive picker — if neither yields an id we throw. The id is then
268
+ * fetched scoped to `agent.id`, so a version that belongs to a different agent
269
+ * fails with a clear ownership error instead of a raw 404 (the version-vs-agent
270
+ * guard from CLI-4).
271
+ */
272
+ async function resolveStrictVersion(client, agent, versionIdArg) {
273
+ let versionId = versionIdArg;
274
+ if (!versionId) {
275
+ const projectRoot = findProjectRoot();
276
+ const projectConfig = projectRoot ? loadProjectConfig(projectRoot) : null;
277
+ versionId = projectConfig?.version_id;
278
+ }
279
+ if (!versionId) {
280
+ throw new CLIError("No version id to act on.", {
281
+ code: "API_CLIENT_ERROR",
282
+ suggestion: "Pass the version id (e.g. `aui version publish <id>`), or set version_id in .auirc (e.g. via `aui version create`).",
283
+ });
284
+ }
285
+ let version;
286
+ try {
287
+ version = await client.agentManagement.getVersion(agent.id, versionId);
288
+ }
289
+ catch {
290
+ throw new CLIError(`Version ${versionId} was not found on agent "${agent.name}" (${agent.id}).`, {
291
+ code: "API_CLIENT_ERROR",
292
+ suggestion: "Confirm the version id belongs to this agent (`aui version list`), or pass --agent-id for the agent that owns it.",
293
+ });
294
+ }
295
+ if (version.agent_id && version.agent_id !== agent.id) {
296
+ throw new CLIError(`Version ${versionId} belongs to agent ${version.agent_id}, not "${agent.name}" (${agent.id}).`, {
297
+ code: "API_CLIENT_ERROR",
298
+ suggestion: "Run from that agent's directory, or pass --agent-id for the owning agent.",
299
+ });
300
+ }
301
+ return version;
302
+ }
171
303
  async function fetchAllVersions(client, agentId, filters) {
172
304
  const all = [];
173
305
  let page = 1;
@@ -183,9 +315,18 @@ async function fetchAllVersions(client, agentId, filters) {
183
315
  // ─── Interactive Menu ───
184
316
  export async function versionMenu() {
185
317
  const { client } = getAuthenticatedClient();
186
- const session = loadSession();
187
318
  log(_jsx(Header, { title: "Version Management" }));
188
- log(_jsx(StatusLine, { kind: "info", label: `Agent: ${session.network_name || session.network_id || "none"}` }));
319
+ // Resolve agent properly (project context takes priority over session)
320
+ let agentLabel;
321
+ try {
322
+ const agent = await resolveAgentId(client);
323
+ agentLabel = agent.name;
324
+ }
325
+ catch {
326
+ const session = loadSession();
327
+ agentLabel = session.network_name || session.network_id || "none";
328
+ }
329
+ log(_jsx(StatusLine, { kind: "info", label: `Agent: ${agentLabel}` }));
189
330
  const { action } = await inquirer.prompt([
190
331
  {
191
332
  type: "list",
@@ -200,6 +341,8 @@ export async function versionMenu() {
200
341
  { name: "Activate a version", value: "activate" },
201
342
  { name: "Archive a version", value: "archive" },
202
343
  new inquirer.Separator(),
344
+ { name: "Browse snapshots", value: "snapshot" },
345
+ new inquirer.Separator(),
203
346
  { name: "Back", value: "back" },
204
347
  ],
205
348
  },
@@ -225,6 +368,11 @@ export async function versionMenu() {
225
368
  case "archive":
226
369
  await versionArchive();
227
370
  break;
371
+ case "snapshot": {
372
+ const { versionSnapshotMenu } = await import("./version-snapshot.js");
373
+ await versionSnapshotMenu();
374
+ break;
375
+ }
228
376
  }
229
377
  }
230
378
  export async function versionList(agentIdArg, options) {
@@ -306,105 +454,230 @@ export async function versionList(agentIdArg, options) {
306
454
  }
307
455
  }
308
456
  export async function versionCreate(options) {
457
+ const json = isJsonMode();
309
458
  const { client, userId } = getAuthenticatedClient();
310
- const agentSpinner = startSpinner("Resolving agent...");
311
459
  let agent;
312
460
  try {
461
+ if (json)
462
+ stderrLog("Resolving agent...");
463
+ const agentSpinner = json ? null : startSpinner("Resolving agent...");
313
464
  agent = await resolveAgentId(client, options.agentId);
314
- agentSpinner.succeed(`Agent: ${agent.name}`);
465
+ if (agentSpinner)
466
+ agentSpinner.succeed(`Agent: ${agent.name}`);
467
+ else
468
+ stderrLog(`Agent: ${agent.name}`);
315
469
  }
316
470
  catch (error) {
317
- agentSpinner.fail("Failed to resolve agent");
318
- log(_jsx(ErrorDisplay, { error: error }));
471
+ if (json) {
472
+ outputJsonError({
473
+ code: "AGENT_RESOLVE_FAILED",
474
+ message: error instanceof Error ? error.message : String(error),
475
+ });
476
+ }
477
+ else {
478
+ log(_jsx(ErrorDisplay, { error: error }));
479
+ }
319
480
  return null;
320
481
  }
321
- let source = options.source;
482
+ const source = options.source;
322
483
  let fromVersion = options.from;
323
- let bumpMode = options.bump;
324
- let label = options.label;
325
- let tags = options.tags?.split(",").map((t) => t.trim()).filter(Boolean);
326
- let notes = options.notes;
327
- if (!source) {
328
- const versions = await fetchAllVersions(client, agent.id);
329
- const { sourceChoice } = await inquirer.prompt([
330
- {
331
- type: "list",
332
- name: "sourceChoice",
333
- message: "How to create the new version?",
334
- choices: [
335
- { name: "Snapshot from current scope", value: "agent-scope" },
336
- ...(versions.length > 0
337
- ? [{ name: "Clone from existing version", value: "version" }]
338
- : []),
339
- ],
340
- },
341
- ]);
342
- source = sourceChoice;
343
- if (source === "version") {
344
- const { selectedVersion } = await inquirer.prompt([
345
- {
346
- type: "list",
347
- name: "selectedVersion",
348
- message: "Clone from which version?",
349
- choices: versions.map((v) => ({
350
- name: `${vLabel(v)} [${v.status}] ${v.label || ""} — ${statsLabel(v.stats)}`,
351
- value: v.id,
352
- })),
353
- pageSize: 15,
354
- },
355
- ]);
356
- fromVersion = selectedVersion;
484
+ const fromTemplate = options.fromTemplate;
485
+ const label = options.label;
486
+ const tags = options.tags?.split(",").map((t) => t.trim()).filter(Boolean);
487
+ const notes = options.notes;
488
+ // ─── Mode-aware, single-step creation (no prompts) ─────────────────
489
+ // `aui version create` is intentionally non-interactive: it inspects the
490
+ // agent's storage mode (the same `detectAgentBundleMode` switch push /
491
+ // pull / import use — honours `AUI_FORCE_AGENT_MODE` and defaults to
492
+ // records on older backends) and creates the draft directly:
493
+ //
494
+ // - bundle-mode → source="version", from_version=<active version>
495
+ // (blob-mode agents have no per-entity records to snapshot, so
496
+ // `agent-scope` would 422). Falls back to --from when given.
497
+ // - records-mode → source="agent-scope".
498
+ //
499
+ // Optional `--source` / `--from` / `--from-template` / `--label` /
500
+ // `--tags` / `--notes` still override; with no flags it "just works".
501
+ const { mode } = await detectAgentBundleMode(client, agent.id, agent);
502
+ const isBundleMode = mode === "bundle";
503
+ const defaultSource = isBundleMode
504
+ ? "version"
505
+ : "agent-scope";
506
+ // Validate source/arg combinations BEFORE the spinner so the user
507
+ // sees the actionable error instead of "Failed to create draft".
508
+ const resolvedSource = (source || defaultSource);
509
+ if (resolvedSource === "version" && !fromVersion) {
510
+ // Auto-pick the agent's active version. If the agent has none
511
+ // (brand-new bundle-mode agent), error with a clear hint.
512
+ if (agent.active_version_id) {
513
+ fromVersion = agent.active_version_id;
357
514
  }
358
- if (fromVersion) {
359
- const { bump } = await inquirer.prompt([
360
- {
361
- type: "list",
362
- name: "bump",
363
- message: "Create as:",
364
- choices: [
365
- { name: "New version number (e.g. v3.0 → v4.0)", value: "version_number" },
366
- { name: "Revision of source (e.g. v3.0 → v3.1)", value: "version_revision_number" },
367
- ],
368
- },
369
- ]);
370
- bumpMode = bump;
515
+ else {
516
+ const errMsg = "source=version requires --from <versionId> (this agent has no active version to clone from).";
517
+ if (json) {
518
+ outputJsonError({ code: "VERSION_CREATE_FROM_REQUIRED", message: errMsg });
519
+ }
520
+ else {
521
+ log(_jsx(ErrorDisplay, { message: errMsg, suggestion: "Pass --from <versionId>, or run `aui version list` to see available versions." }));
522
+ }
523
+ return null;
371
524
  }
372
- const meta = await inquirer.prompt([
373
- { type: "input", name: "label", message: "Label (optional):", default: "" },
374
- { type: "input", name: "tags", message: "Tags (comma-separated, optional):", default: "" },
375
- { type: "input", name: "notes", message: "Notes (optional):", default: "" },
376
- ]);
377
- if (meta.label)
378
- label = meta.label;
379
- if (meta.tags)
380
- tags = meta.tags.split(",").map((t) => t.trim()).filter(Boolean);
381
- if (meta.notes)
382
- notes = meta.notes;
383
- }
384
- const spinner = startSpinner("Creating draft version...");
525
+ }
526
+ if (resolvedSource === "template" && !fromTemplate) {
527
+ const errMsg = "source=template requires --from-template <templateAgentId>.";
528
+ if (json) {
529
+ outputJsonError({
530
+ code: "VERSION_CREATE_FROM_TEMPLATE_REQUIRED",
531
+ message: errMsg,
532
+ });
533
+ }
534
+ else {
535
+ log(_jsx(ErrorDisplay, { message: errMsg, suggestion: "Pass --from-template <agentManagementId> pointing at a kind=template agent." }));
536
+ }
537
+ return null;
538
+ }
539
+ if (resolvedSource === "agent-scope" && isBundleMode) {
540
+ const errMsg = "source=agent-scope is records-mode only. This agent is in blob-mode (bundle_mode=true).";
541
+ if (json) {
542
+ outputJsonError({ code: "VERSION_CREATE_SOURCE_MODE_MISMATCH", message: errMsg });
543
+ }
544
+ else {
545
+ log(_jsx(ErrorDisplay, { message: errMsg, suggestion: "Use --source version --from <versionId> or --source template --from-template <templateAgentId>." }));
546
+ }
547
+ return null;
548
+ }
549
+ if (resolvedSource === "template" && !isBundleMode) {
550
+ const errMsg = "source=template is blob-mode only. This agent is in records-mode (bundle_mode=false).";
551
+ if (json) {
552
+ outputJsonError({ code: "VERSION_CREATE_SOURCE_MODE_MISMATCH", message: errMsg });
553
+ }
554
+ else {
555
+ log(_jsx(ErrorDisplay, { message: errMsg, suggestion: "Use --source version --from <versionId> or --source agent-scope (records mode default)." }));
556
+ }
557
+ return null;
558
+ }
559
+ if (json)
560
+ stderrLog("Creating draft version...");
561
+ const spinner = json ? null : startSpinner("Creating draft version...");
385
562
  try {
386
563
  const draft = await client.agentManagement.createDraft(agent.id, {
387
- source: source || "agent-scope",
388
- ...(fromVersion ? { from_version: fromVersion } : {}),
389
- bump_mode: bumpMode || (fromVersion ? "version_revision_number" : "version_number"),
564
+ source: resolvedSource,
565
+ // `from_version` is only meaningful for source=version. A stray `--from`
566
+ // on a records agent (source=agent-scope) used to leak through and 422
567
+ // server-side ("from_version must not be set when source=agent-scope").
568
+ ...(resolvedSource === "version" && fromVersion
569
+ ? { from_version: fromVersion }
570
+ : {}),
571
+ ...(fromTemplate ? { from_template: fromTemplate } : {}),
572
+ bump_mode: "version_number",
390
573
  created_by: userId,
391
574
  ...(label ? { label } : {}),
392
575
  ...(tags && tags.length > 0 ? { tags } : {}),
393
576
  ...(notes ? { notes } : {}),
394
577
  });
395
- spinner.succeed(`Draft created: ${vLabel(draft)} [${draft.status}]`);
578
+ if (spinner)
579
+ spinner.succeed(`Draft created: ${vLabel(draft)} [${draft.status}]`);
580
+ // ─── Repoint .auirc at the new draft (default behaviour) ───
581
+ // Every `version create` now updates the project's `.auirc` so the very
582
+ // next `aui push` / `aui pull` targets the draft you just made — no
583
+ // separate `--use` step. We write three fields:
584
+ // • `version_id` → the new draft's id.
585
+ // • `version_label` → the draft's custom label if given, else `v{version_number}`.
586
+ // • `version_tag` → the draft's revision tag in the canonical
587
+ // `v{version_number}.{version_revision_number}` form
588
+ // (e.g. `v15.0`) — the same format `aui push` / `pull`
589
+ // persist — preferring a server-returned `version_tag`
590
+ // when the create response carries one.
591
+ //
592
+ // Guard: ONLY repoint a `.auirc` that actually belongs to THIS agent —
593
+ // i.e. the draft was created inside this agent's own project folder.
594
+ // Checked unconditionally (not just when `--agent-id` is passed): if the
595
+ // nearest `.auirc` up the tree tracks a different agent, we leave it
596
+ // alone rather than silently overwriting an unrelated project's
597
+ // `version_id`. Without `--agent-id` the agent was resolved from this
598
+ // `.auirc` so it matches by construction; a `.auirc` with no agent
599
+ // identifiers is treated as a match (nothing to conflict with).
600
+ const newVersionLabel = draft.label || vLabel(draft);
601
+ // Prefer a server-supplied `version_tag` if the create response carries one
602
+ // (not in the typed shape, so probe defensively); otherwise derive the
603
+ // canonical `v{number}.{revision}` tag from the draft's numbers.
604
+ const draftWithTag = draft;
605
+ const newVersionTag = typeof draftWithTag.version_tag === "string" && draftWithTag.version_tag
606
+ ? draftWithTag.version_tag
607
+ : `v${draft.version_number}.${draft.version_revision_number}`;
608
+ let auircUpdated = false;
609
+ let auircPath;
610
+ let auircSkippedReason;
611
+ const projectRoot = findProjectRoot();
612
+ if (!projectRoot) {
613
+ auircSkippedReason = "no-auirc";
614
+ }
615
+ else {
616
+ const projectConfig = loadProjectConfig(projectRoot);
617
+ if (!projectConfig) {
618
+ auircSkippedReason = "no-auirc";
619
+ }
620
+ else if (!agentMatchesProject(agent, projectConfig)) {
621
+ auircSkippedReason = "foreign-agent";
622
+ }
623
+ else {
624
+ const updated = {
625
+ ...projectConfig,
626
+ version_id: draft.id,
627
+ version_label: newVersionLabel,
628
+ version_tag: newVersionTag,
629
+ };
630
+ saveProjectConfig(updated, projectRoot);
631
+ auircUpdated = true;
632
+ auircPath = `${projectRoot}/.auirc`;
633
+ }
634
+ }
635
+ if (json) {
636
+ outputJson({
637
+ agent: { id: agent.id, name: agent.name },
638
+ draft: {
639
+ id: draft.id,
640
+ version: vLabel(draft),
641
+ version_number: draft.version_number,
642
+ version_revision_number: draft.version_revision_number,
643
+ version_tag: newVersionTag,
644
+ status: draft.status,
645
+ label: draft.label,
646
+ tags: draft.tags,
647
+ notes: draft.notes,
648
+ parent_version_id: draft.parent_version_id,
649
+ stats: draft.stats,
650
+ created_at: draft.created_at,
651
+ created_by: draft.created_by,
652
+ },
653
+ auirc_updated: auircUpdated,
654
+ ...(auircPath ? { auirc_path: auircPath } : {}),
655
+ ...(auircSkippedReason ? { auirc_skipped_reason: auircSkippedReason } : {}),
656
+ });
657
+ return draft;
658
+ }
396
659
  log(_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(KeyValueGroup, { items: [
397
660
  { label: "Version ID:", value: draft.id },
398
661
  { label: "Version:", value: vLabel(draft) },
662
+ { label: "Tag:", value: newVersionTag },
399
663
  { label: "Status:", value: draft.status },
400
664
  ...(draft.label ? [{ label: "Label:", value: draft.label }] : []),
401
665
  { label: "Entities:", value: String(draft.stats?.total ?? 0) },
402
- ] }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "cyan", bold: true, children: "\u2192 " }), _jsx(Text, { children: "Next: " }), _jsx(Text, { bold: true, children: "aui version publish" }), _jsx(Text, { color: "gray", children: " to lock this version" })] }), _jsxs(Box, { children: [_jsx(Text, { color: "gray", children: " Use " }), _jsx(Text, { bold: true, children: "aui version list" }), _jsx(Text, { color: "gray", children: " to see all versions and their status" })] })] }));
666
+ ] }), auircUpdated && (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "green", bold: true, children: "\u2713 " }), _jsx(Text, { color: "gray", children: ".auirc updated \u2192 " }), _jsx(Text, { bold: true, children: newVersionLabel }), _jsx(Text, { color: "gray", children: " \u2014 " }), _jsx(Text, { bold: true, children: "aui push" }), _jsx(Text, { color: "gray", children: " / " }), _jsx(Text, { bold: true, children: "aui pull" }), _jsx(Text, { color: "gray", children: " now target this draft" })] })), auircSkippedReason === "foreign-agent" && (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "yellow", bold: true, children: "! " }), _jsx(Text, { color: "gray", children: ".auirc left unchanged \u2014 it tracks a different agent than the one this draft belongs to." })] })), auircSkippedReason === "no-auirc" && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: " No .auirc in this directory \u2014 skipped project update." }) })), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "cyan", bold: true, children: "\u2192 " }), _jsx(Text, { children: "Next: " }), _jsx(Text, { bold: true, children: "aui version publish" }), _jsx(Text, { color: "gray", children: " to lock this version" })] }), _jsxs(Box, { children: [_jsx(Text, { color: "gray", children: " Use " }), _jsx(Text, { bold: true, children: "aui version list" }), _jsx(Text, { color: "gray", children: " to see all versions and their status" })] })] }));
403
667
  return draft;
404
668
  }
405
669
  catch (error) {
406
- spinner.fail("Failed to create draft");
407
- log(_jsx(ErrorDisplay, { error: error }));
670
+ if (spinner)
671
+ spinner.fail("Failed to create draft");
672
+ if (json) {
673
+ outputJsonError({
674
+ code: "VERSION_CREATE_FAILED",
675
+ message: error instanceof Error ? error.message : String(error),
676
+ });
677
+ }
678
+ else {
679
+ log(_jsx(ErrorDisplay, { error: error }));
680
+ }
408
681
  return null;
409
682
  }
410
683
  }
@@ -469,46 +742,33 @@ export async function versionGet(versionIdArg, agentIdArg) {
469
742
  // ─── Publish Version ───
470
743
  export async function versionPublish(versionIdArg, agentIdArg) {
471
744
  const { client, userId } = getAuthenticatedClient();
472
- const agent = await resolveWithSpinner(client, agentIdArg);
473
- if (!agent)
474
- return;
475
- let versionId = versionIdArg;
476
- if (!versionId) {
477
- const versions = await fetchAllVersions(client, agent.id);
478
- const drafts = versions.filter((v) => v.status === "draft");
479
- if (drafts.length === 0) {
480
- log(_jsx(StatusLine, { kind: "warning", label: "No draft versions to publish." }));
481
- return;
482
- }
483
- const { selected } = await inquirer.prompt([
484
- {
485
- type: "list",
486
- name: "selected",
487
- message: "Select draft to publish:",
488
- choices: drafts.map((v) => ({
489
- name: `${vLabel(v)} — ${statsLabel(v.stats)} ${v.label || ""}`,
490
- value: v.id,
491
- })),
492
- pageSize: 15,
493
- },
494
- ]);
495
- versionId = selected;
745
+ // Strict, non-interactive resolution: agent + version come from --agent-id /
746
+ // <version-id> or the project's .auirc, never the session and never a picker.
747
+ let agent;
748
+ let version;
749
+ const resolveSpinner = startSpinner("Resolving agent and version...");
750
+ try {
751
+ agent = await resolveStrictAgent(client, agentIdArg);
752
+ version = await resolveStrictVersion(client, agent, versionIdArg);
753
+ resolveSpinner.succeed(`Target: ${agent.name} ${vLabel(version)} [${version.status}]`);
496
754
  }
497
- const { confirm } = await inquirer.prompt([
498
- {
499
- type: "confirm",
500
- name: "confirm",
501
- message: "Publishing locks this version permanently. Continue?",
502
- default: false,
503
- },
504
- ]);
505
- if (!confirm) {
506
- log(_jsx(StatusLine, { kind: "muted", label: "Cancelled." }));
755
+ catch (error) {
756
+ // Strict-resolution failures (not in an agent dir, unknown/foreign version)
757
+ // propagate so `handleError` renders them and exits non-zero — automation
758
+ // must be able to tell a refused mutation from a successful one.
759
+ resolveSpinner.stop();
760
+ throw error;
761
+ }
762
+ if (version.status.toLowerCase() !== "draft") {
763
+ log(_jsx(StatusLine, { kind: "warning", label: `${vLabel(version)} is ${version.status}, not a draft — only drafts can be published.` }));
507
764
  return;
508
765
  }
766
+ // No confirmation prompt: the target was resolved deterministically from
767
+ // --agent-id / <version-id> / .auirc and echoed above. These commands act on
768
+ // exactly that target, always non-interactively.
509
769
  const spinner = startSpinner("Publishing version...");
510
770
  try {
511
- const published = await client.agentManagement.publishVersion(agent.id, versionId, userId);
771
+ const published = await client.agentManagement.publishVersion(agent.id, version.id, userId);
512
772
  spinner.succeed(`Published: ${vLabel(published)} [${published.status}]`);
513
773
  log(_jsxs(Box, { paddingX: 1, children: [_jsx(Text, { color: "cyan", bold: true, children: "\u2192 " }), _jsx(Text, { children: "Next: " }), _jsx(Text, { bold: true, children: "aui version activate" }), _jsx(Text, { color: "gray", children: " to make this the live configuration" })] }));
514
774
  }
@@ -520,49 +780,34 @@ export async function versionPublish(versionIdArg, agentIdArg) {
520
780
  // ─── Activate Version ───
521
781
  export async function versionActivate(versionIdArg, agentIdArg) {
522
782
  const { client } = getAuthenticatedClient();
523
- const agent = await resolveWithSpinner(client, agentIdArg);
524
- if (!agent)
783
+ // Strict, non-interactive resolution (see versionPublish).
784
+ let agent;
785
+ let version;
786
+ const resolveSpinner = startSpinner("Resolving agent and version...");
787
+ try {
788
+ agent = await resolveStrictAgent(client, agentIdArg);
789
+ version = await resolveStrictVersion(client, agent, versionIdArg);
790
+ resolveSpinner.succeed(`Target: ${agent.name} → ${vLabel(version)} [${version.status}]`);
791
+ }
792
+ catch (error) {
793
+ // Strict-resolution failures (not in an agent dir, unknown/foreign version)
794
+ // propagate so `handleError` renders them and exits non-zero — automation
795
+ // must be able to tell a refused mutation from a successful one.
796
+ resolveSpinner.stop();
797
+ throw error;
798
+ }
799
+ if (version.status.toLowerCase() !== "published") {
800
+ log(_jsx(StatusLine, { kind: "warning", label: `${vLabel(version)} is ${version.status} — only published versions can be activated.` }));
525
801
  return;
526
- let versionId = versionIdArg;
527
- if (!versionId) {
528
- const versions = await fetchAllVersions(client, agent.id);
529
- const published = versions.filter((v) => v.status === "published");
530
- if (published.length === 0) {
531
- log(_jsx(StatusLine, { kind: "warning", label: "No published versions to activate." }));
532
- return;
533
- }
534
- const { selected } = await inquirer.prompt([
535
- {
536
- type: "list",
537
- name: "selected",
538
- message: "Select version to activate:",
539
- choices: published.map((v) => {
540
- const isActive = v.id === agent.active_version_id;
541
- return {
542
- name: `${vLabel(v)} ${isActive ? chalk.green("← active") : ""} — ${statsLabel(v.stats)}`,
543
- value: v.id,
544
- };
545
- }),
546
- pageSize: 15,
547
- },
548
- ]);
549
- versionId = selected;
550
802
  }
551
- const { confirm } = await inquirer.prompt([
552
- {
553
- type: "confirm",
554
- name: "confirm",
555
- message: `Activate this version as the live configuration?`,
556
- default: true,
557
- },
558
- ]);
559
- if (!confirm) {
560
- log(_jsx(StatusLine, { kind: "muted", label: "Cancelled." }));
803
+ if (version.id === agent.active_version_id) {
804
+ log(_jsx(StatusLine, { kind: "info", label: `${vLabel(version)} is already the live version. Nothing to do.` }));
561
805
  return;
562
806
  }
807
+ // No confirmation prompt — act on the resolved target directly (see publish).
563
808
  const spinner = startSpinner("Activating version...");
564
809
  try {
565
- await client.agentManagement.activateVersion(agent.id, versionId);
810
+ await client.agentManagement.activateVersion(agent.id, version.id);
566
811
  spinner.succeed(`Version activated successfully`);
567
812
  log(_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsxs(Box, { children: [_jsx(Text, { color: "green", bold: true, children: "\u2713 " }), _jsx(Text, { children: "This version is now live in production" })] }), _jsxs(Box, { children: [_jsx(Text, { color: "gray", children: " Use " }), _jsx(Text, { bold: true, children: "aui version list" }), _jsx(Text, { color: "gray", children: " to see all versions and their status" })] })] }));
568
813
  }
@@ -574,46 +819,34 @@ export async function versionActivate(versionIdArg, agentIdArg) {
574
819
  // ─── Archive Version ───
575
820
  export async function versionArchive(versionIdArg, agentIdArg) {
576
821
  const { client } = getAuthenticatedClient();
577
- const agent = await resolveWithSpinner(client, agentIdArg);
578
- if (!agent)
822
+ // Strict, non-interactive resolution (see versionPublish).
823
+ let agent;
824
+ let version;
825
+ const resolveSpinner = startSpinner("Resolving agent and version...");
826
+ try {
827
+ agent = await resolveStrictAgent(client, agentIdArg);
828
+ version = await resolveStrictVersion(client, agent, versionIdArg);
829
+ resolveSpinner.succeed(`Target: ${agent.name} → ${vLabel(version)} [${version.status}]`);
830
+ }
831
+ catch (error) {
832
+ // Strict-resolution failures (not in an agent dir, unknown/foreign version)
833
+ // propagate so `handleError` renders them and exits non-zero — automation
834
+ // must be able to tell a refused mutation from a successful one.
835
+ resolveSpinner.stop();
836
+ throw error;
837
+ }
838
+ if (version.status.toLowerCase() !== "published") {
839
+ log(_jsx(StatusLine, { kind: "warning", label: `${vLabel(version)} is ${version.status} — only published versions can be archived.` }));
579
840
  return;
580
- let versionId = versionIdArg;
581
- if (!versionId) {
582
- const versions = await fetchAllVersions(client, agent.id);
583
- const archivable = versions.filter((v) => v.status === "published" && v.id !== agent.active_version_id);
584
- if (archivable.length === 0) {
585
- log(_jsx(StatusLine, { kind: "warning", label: "No versions available to archive (must be published and not active)." }));
586
- return;
587
- }
588
- const { selected } = await inquirer.prompt([
589
- {
590
- type: "list",
591
- name: "selected",
592
- message: "Select version to archive:",
593
- choices: archivable.map((v) => ({
594
- name: `${vLabel(v)} — ${statsLabel(v.stats)} ${v.label || ""}`,
595
- value: v.id,
596
- })),
597
- pageSize: 15,
598
- },
599
- ]);
600
- versionId = selected;
601
841
  }
602
- const { confirm } = await inquirer.prompt([
603
- {
604
- type: "confirm",
605
- name: "confirm",
606
- message: "Archived versions cannot be activated. They can still be viewed and cloned. Continue?",
607
- default: false,
608
- },
609
- ]);
610
- if (!confirm) {
611
- log(_jsx(StatusLine, { kind: "muted", label: "Cancelled." }));
842
+ if (version.id === agent.active_version_id) {
843
+ log(_jsx(StatusLine, { kind: "warning", label: `${vLabel(version)} is the live version — activate another version before archiving it.` }));
612
844
  return;
613
845
  }
846
+ // No confirmation prompt — act on the resolved target directly (see publish).
614
847
  const spinner = startSpinner("Archiving version...");
615
848
  try {
616
- const archived = await client.agentManagement.archiveVersion(agent.id, versionId);
849
+ const archived = await client.agentManagement.archiveVersion(agent.id, version.id);
617
850
  spinner.succeed(`Archived: ${vLabel(archived)} [${archived.status}]`);
618
851
  }
619
852
  catch (error) {