@knowzai/cli 0.1.0 → 0.3.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 (340) hide show
  1. package/assets/portable/.env.example +3 -0
  2. package/assets/portable/docker-compose.yml +18 -0
  3. package/assets/portable/releases.json +22 -0
  4. package/assets/selfhosted/.env.example +19 -0
  5. package/assets/selfhosted/docker-compose.yml +96 -0
  6. package/assets/selfhosted/releases.json +28 -0
  7. package/dist/.tsbuildinfo +1 -1
  8. package/dist/base-command.d.ts +21 -2
  9. package/dist/base-command.d.ts.map +1 -1
  10. package/dist/base-command.js +47 -4
  11. package/dist/base-command.js.map +1 -1
  12. package/dist/commands/ask.d.ts.map +1 -1
  13. package/dist/commands/ask.js +5 -1
  14. package/dist/commands/ask.js.map +1 -1
  15. package/dist/commands/auth/status.d.ts +1 -1
  16. package/dist/commands/auth/status.d.ts.map +1 -1
  17. package/dist/commands/auth/status.js +4 -0
  18. package/dist/commands/auth/status.js.map +1 -1
  19. package/dist/commands/chat.d.ts +5 -0
  20. package/dist/commands/chat.d.ts.map +1 -1
  21. package/dist/commands/chat.js +32 -13
  22. package/dist/commands/chat.js.map +1 -1
  23. package/dist/commands/config/get.d.ts.map +1 -1
  24. package/dist/commands/config/get.js +3 -1
  25. package/dist/commands/config/get.js.map +1 -1
  26. package/dist/commands/config/list.d.ts.map +1 -1
  27. package/dist/commands/config/list.js +12 -4
  28. package/dist/commands/config/list.js.map +1 -1
  29. package/dist/commands/doctor.js +1 -1
  30. package/dist/commands/doctor.js.map +1 -1
  31. package/dist/commands/down.d.ts +9 -0
  32. package/dist/commands/down.d.ts.map +1 -1
  33. package/dist/commands/down.js +16 -1
  34. package/dist/commands/down.js.map +1 -1
  35. package/dist/commands/export.d.ts +27 -0
  36. package/dist/commands/export.d.ts.map +1 -0
  37. package/dist/commands/export.js +155 -0
  38. package/dist/commands/export.js.map +1 -0
  39. package/dist/commands/import.d.ts +27 -0
  40. package/dist/commands/import.d.ts.map +1 -0
  41. package/dist/commands/import.js +124 -0
  42. package/dist/commands/import.js.map +1 -0
  43. package/dist/commands/index/scan.d.ts.map +1 -1
  44. package/dist/commands/index/scan.js +24 -5
  45. package/dist/commands/index/scan.js.map +1 -1
  46. package/dist/commands/knowledge/amend.d.ts +1 -0
  47. package/dist/commands/knowledge/amend.d.ts.map +1 -1
  48. package/dist/commands/knowledge/amend.js +11 -2
  49. package/dist/commands/knowledge/amend.js.map +1 -1
  50. package/dist/commands/knowledge/attach.d.ts +19 -0
  51. package/dist/commands/knowledge/attach.d.ts.map +1 -0
  52. package/dist/commands/knowledge/attach.js +51 -0
  53. package/dist/commands/knowledge/attach.js.map +1 -0
  54. package/dist/commands/knowledge/create.d.ts +9 -1
  55. package/dist/commands/knowledge/create.d.ts.map +1 -1
  56. package/dist/commands/knowledge/create.js +26 -4
  57. package/dist/commands/knowledge/create.js.map +1 -1
  58. package/dist/commands/knowledge/update.d.ts +1 -0
  59. package/dist/commands/knowledge/update.d.ts.map +1 -1
  60. package/dist/commands/knowledge/update.js +4 -1
  61. package/dist/commands/knowledge/update.js.map +1 -1
  62. package/dist/commands/login.d.ts +19 -3
  63. package/dist/commands/login.d.ts.map +1 -1
  64. package/dist/commands/login.js +113 -64
  65. package/dist/commands/login.js.map +1 -1
  66. package/dist/commands/logout.d.ts +2 -0
  67. package/dist/commands/logout.d.ts.map +1 -1
  68. package/dist/commands/logout.js +35 -1
  69. package/dist/commands/logout.js.map +1 -1
  70. package/dist/commands/mcp/serve.d.ts +16 -0
  71. package/dist/commands/mcp/serve.d.ts.map +1 -0
  72. package/dist/commands/mcp/serve.js +50 -0
  73. package/dist/commands/mcp/serve.js.map +1 -0
  74. package/dist/commands/menu.d.ts.map +1 -1
  75. package/dist/commands/menu.js +39 -3
  76. package/dist/commands/menu.js.map +1 -1
  77. package/dist/commands/peer/accept-fingerprint.d.ts +17 -0
  78. package/dist/commands/peer/accept-fingerprint.d.ts.map +1 -0
  79. package/dist/commands/peer/accept-fingerprint.js +35 -0
  80. package/dist/commands/peer/accept-fingerprint.js.map +1 -0
  81. package/dist/commands/peer/add.d.ts +22 -0
  82. package/dist/commands/peer/add.d.ts.map +1 -0
  83. package/dist/commands/peer/add.js +44 -0
  84. package/dist/commands/peer/add.js.map +1 -0
  85. package/dist/commands/peer/cancel.d.ts +13 -0
  86. package/dist/commands/peer/cancel.d.ts.map +1 -0
  87. package/dist/commands/peer/cancel.js +20 -0
  88. package/dist/commands/peer/cancel.js.map +1 -0
  89. package/dist/commands/peer/link.d.ts +16 -0
  90. package/dist/commands/peer/link.d.ts.map +1 -0
  91. package/dist/commands/peer/link.js +32 -0
  92. package/dist/commands/peer/link.js.map +1 -0
  93. package/dist/commands/peer/links.d.ts +12 -0
  94. package/dist/commands/peer/links.d.ts.map +1 -0
  95. package/dist/commands/peer/links.js +25 -0
  96. package/dist/commands/peer/links.js.map +1 -0
  97. package/dist/commands/peer/list.d.ts +10 -0
  98. package/dist/commands/peer/list.d.ts.map +1 -0
  99. package/dist/commands/peer/list.js +22 -0
  100. package/dist/commands/peer/list.js.map +1 -0
  101. package/dist/commands/peer/pull.d.ts +19 -0
  102. package/dist/commands/peer/pull.d.ts.map +1 -0
  103. package/dist/commands/peer/pull.js +30 -0
  104. package/dist/commands/peer/pull.js.map +1 -0
  105. package/dist/commands/peer/push.d.ts +19 -0
  106. package/dist/commands/peer/push.d.ts.map +1 -0
  107. package/dist/commands/peer/push.js +30 -0
  108. package/dist/commands/peer/push.js.map +1 -0
  109. package/dist/commands/peer/remove.d.ts +12 -0
  110. package/dist/commands/peer/remove.d.ts.map +1 -0
  111. package/dist/commands/peer/remove.js +19 -0
  112. package/dist/commands/peer/remove.js.map +1 -0
  113. package/dist/commands/peer/rotate-key.d.ts +14 -0
  114. package/dist/commands/peer/rotate-key.d.ts.map +1 -0
  115. package/dist/commands/peer/rotate-key.js +26 -0
  116. package/dist/commands/peer/rotate-key.js.map +1 -0
  117. package/dist/commands/peer/run.d.ts +13 -0
  118. package/dist/commands/peer/run.d.ts.map +1 -0
  119. package/dist/commands/peer/run.js +31 -0
  120. package/dist/commands/peer/run.js.map +1 -0
  121. package/dist/commands/peer/runs.d.ts +15 -0
  122. package/dist/commands/peer/runs.d.ts.map +1 -0
  123. package/dist/commands/peer/runs.js +32 -0
  124. package/dist/commands/peer/runs.js.map +1 -0
  125. package/dist/commands/peer/test.d.ts +13 -0
  126. package/dist/commands/peer/test.d.ts.map +1 -0
  127. package/dist/commands/peer/test.js +30 -0
  128. package/dist/commands/peer/test.js.map +1 -0
  129. package/dist/commands/peer/unlink.d.ts +13 -0
  130. package/dist/commands/peer/unlink.d.ts.map +1 -0
  131. package/dist/commands/peer/unlink.js +20 -0
  132. package/dist/commands/peer/unlink.js.map +1 -0
  133. package/dist/commands/pg/status.d.ts.map +1 -1
  134. package/dist/commands/pg/status.js +6 -3
  135. package/dist/commands/pg/status.js.map +1 -1
  136. package/dist/commands/pg/up.d.ts.map +1 -1
  137. package/dist/commands/pg/up.js +9 -4
  138. package/dist/commands/pg/up.js.map +1 -1
  139. package/dist/commands/platform/status.d.ts.map +1 -1
  140. package/dist/commands/platform/status.js +4 -4
  141. package/dist/commands/platform/status.js.map +1 -1
  142. package/dist/commands/profile/purge.d.ts +20 -0
  143. package/dist/commands/profile/purge.d.ts.map +1 -0
  144. package/dist/commands/profile/purge.js +43 -0
  145. package/dist/commands/profile/purge.js.map +1 -0
  146. package/dist/commands/repo/context.d.ts.map +1 -1
  147. package/dist/commands/repo/context.js +3 -1
  148. package/dist/commands/repo/context.js.map +1 -1
  149. package/dist/commands/repo/graph.d.ts +3 -6
  150. package/dist/commands/repo/graph.d.ts.map +1 -1
  151. package/dist/commands/repo/graph.js +24 -40
  152. package/dist/commands/repo/graph.js.map +1 -1
  153. package/dist/commands/repo/index/index.d.ts +1 -0
  154. package/dist/commands/repo/index/index.d.ts.map +1 -1
  155. package/dist/commands/repo/index/index.js +100 -12
  156. package/dist/commands/repo/index/index.js.map +1 -1
  157. package/dist/commands/repo/search.d.ts.map +1 -1
  158. package/dist/commands/repo/search.js +2 -0
  159. package/dist/commands/repo/search.js.map +1 -1
  160. package/dist/commands/repo/setup.d.ts +9 -2
  161. package/dist/commands/repo/setup.d.ts.map +1 -1
  162. package/dist/commands/repo/setup.js +84 -8
  163. package/dist/commands/repo/setup.js.map +1 -1
  164. package/dist/commands/status.d.ts +4 -0
  165. package/dist/commands/status.d.ts.map +1 -1
  166. package/dist/commands/status.js +21 -3
  167. package/dist/commands/status.js.map +1 -1
  168. package/dist/commands/transfer.d.ts +30 -0
  169. package/dist/commands/transfer.d.ts.map +1 -0
  170. package/dist/commands/transfer.js +140 -0
  171. package/dist/commands/transfer.js.map +1 -0
  172. package/dist/commands/tui.js +1 -1
  173. package/dist/commands/tui.js.map +1 -1
  174. package/dist/commands/up.d.ts +6 -27
  175. package/dist/commands/up.d.ts.map +1 -1
  176. package/dist/commands/up.js +63 -21
  177. package/dist/commands/up.js.map +1 -1
  178. package/dist/lib/attach.d.ts +48 -0
  179. package/dist/lib/attach.d.ts.map +1 -0
  180. package/dist/lib/attach.js +91 -0
  181. package/dist/lib/attach.js.map +1 -0
  182. package/dist/lib/chat-render.d.ts +39 -0
  183. package/dist/lib/chat-render.d.ts.map +1 -0
  184. package/dist/lib/chat-render.js +77 -0
  185. package/dist/lib/chat-render.js.map +1 -0
  186. package/dist/lib/cmek-guard.d.ts +52 -0
  187. package/dist/lib/cmek-guard.d.ts.map +1 -0
  188. package/dist/lib/cmek-guard.js +73 -0
  189. package/dist/lib/cmek-guard.js.map +1 -0
  190. package/dist/lib/content.d.ts +7 -0
  191. package/dist/lib/content.d.ts.map +1 -1
  192. package/dist/lib/content.js +9 -2
  193. package/dist/lib/content.js.map +1 -1
  194. package/dist/lib/credential-purge.d.ts +52 -0
  195. package/dist/lib/credential-purge.d.ts.map +1 -0
  196. package/dist/lib/credential-purge.js +37 -0
  197. package/dist/lib/credential-purge.js.map +1 -0
  198. package/dist/lib/ingest.d.ts.map +1 -1
  199. package/dist/lib/ingest.js +7 -3
  200. package/dist/lib/ingest.js.map +1 -1
  201. package/dist/lib/local-mcp-server.d.ts +82 -0
  202. package/dist/lib/local-mcp-server.d.ts.map +1 -0
  203. package/dist/lib/local-mcp-server.js +252 -0
  204. package/dist/lib/local-mcp-server.js.map +1 -0
  205. package/dist/lib/local-mcp-stdio.d.ts +8 -0
  206. package/dist/lib/local-mcp-stdio.d.ts.map +1 -0
  207. package/dist/lib/local-mcp-stdio.js +50 -0
  208. package/dist/lib/local-mcp-stdio.js.map +1 -0
  209. package/dist/lib/login-guided.d.ts +20 -0
  210. package/dist/lib/login-guided.d.ts.map +1 -0
  211. package/dist/lib/login-guided.js +89 -0
  212. package/dist/lib/login-guided.js.map +1 -0
  213. package/dist/lib/login.d.ts +58 -12
  214. package/dist/lib/login.d.ts.map +1 -1
  215. package/dist/lib/login.js +170 -12
  216. package/dist/lib/login.js.map +1 -1
  217. package/dist/lib/onboarding.d.ts +56 -0
  218. package/dist/lib/onboarding.d.ts.map +1 -0
  219. package/dist/lib/onboarding.js +67 -0
  220. package/dist/lib/onboarding.js.map +1 -0
  221. package/dist/lib/peer-command.d.ts +51 -0
  222. package/dist/lib/peer-command.d.ts.map +1 -0
  223. package/dist/lib/peer-command.js +120 -0
  224. package/dist/lib/peer-command.js.map +1 -0
  225. package/dist/lib/peer-support.d.ts +67 -0
  226. package/dist/lib/peer-support.d.ts.map +1 -0
  227. package/dist/lib/peer-support.js +154 -0
  228. package/dist/lib/peer-support.js.map +1 -0
  229. package/dist/lib/platform-edition.d.ts +34 -0
  230. package/dist/lib/platform-edition.d.ts.map +1 -0
  231. package/dist/lib/platform-edition.js +47 -0
  232. package/dist/lib/platform-edition.js.map +1 -0
  233. package/dist/lib/platform-frontdoor-runtime.d.ts.map +1 -1
  234. package/dist/lib/platform-frontdoor-runtime.js +32 -1
  235. package/dist/lib/platform-frontdoor-runtime.js.map +1 -1
  236. package/dist/lib/platform-frontdoor.d.ts +26 -2
  237. package/dist/lib/platform-frontdoor.d.ts.map +1 -1
  238. package/dist/lib/platform-frontdoor.js +363 -126
  239. package/dist/lib/platform-frontdoor.js.map +1 -1
  240. package/dist/lib/platform-lifecycle.d.ts +7 -0
  241. package/dist/lib/platform-lifecycle.d.ts.map +1 -1
  242. package/dist/lib/platform-lifecycle.js +14 -3
  243. package/dist/lib/platform-lifecycle.js.map +1 -1
  244. package/dist/lib/platform-onboarding.d.ts +1 -0
  245. package/dist/lib/platform-onboarding.d.ts.map +1 -1
  246. package/dist/lib/platform-onboarding.js +13 -2
  247. package/dist/lib/platform-onboarding.js.map +1 -1
  248. package/dist/lib/platform-profile-purge.d.ts +1 -1
  249. package/dist/lib/platform-profile-purge.d.ts.map +1 -1
  250. package/dist/lib/platform-profile-purge.js +2 -1
  251. package/dist/lib/platform-profile-purge.js.map +1 -1
  252. package/dist/lib/platform-provider-prompt.d.ts +4 -0
  253. package/dist/lib/platform-provider-prompt.d.ts.map +1 -1
  254. package/dist/lib/platform-provider-prompt.js +4 -0
  255. package/dist/lib/platform-provider-prompt.js.map +1 -1
  256. package/dist/lib/platform-release-manifest.d.ts +15 -1
  257. package/dist/lib/platform-release-manifest.d.ts.map +1 -1
  258. package/dist/lib/platform-release-manifest.js +24 -0
  259. package/dist/lib/platform-release-manifest.js.map +1 -1
  260. package/dist/lib/portability-shared.d.ts +49 -0
  261. package/dist/lib/portability-shared.d.ts.map +1 -0
  262. package/dist/lib/portability-shared.js +220 -0
  263. package/dist/lib/portability-shared.js.map +1 -0
  264. package/dist/lib/project-mcp-config.d.ts +14 -0
  265. package/dist/lib/project-mcp-config.d.ts.map +1 -0
  266. package/dist/lib/project-mcp-config.js +78 -0
  267. package/dist/lib/project-mcp-config.js.map +1 -0
  268. package/dist/lib/release-package-graph.d.ts +154 -0
  269. package/dist/lib/release-package-graph.d.ts.map +1 -0
  270. package/dist/lib/release-package-graph.js +249 -0
  271. package/dist/lib/release-package-graph.js.map +1 -0
  272. package/dist/lib/repo-binding.d.ts +7 -2
  273. package/dist/lib/repo-binding.d.ts.map +1 -1
  274. package/dist/lib/repo-binding.js +131 -18
  275. package/dist/lib/repo-binding.js.map +1 -1
  276. package/dist/lib/repo-command-support.d.ts +3 -1
  277. package/dist/lib/repo-command-support.d.ts.map +1 -1
  278. package/dist/lib/repo-command-support.js.map +1 -1
  279. package/dist/lib/repo-local-mcp-backend.d.ts +65 -0
  280. package/dist/lib/repo-local-mcp-backend.d.ts.map +1 -0
  281. package/dist/lib/repo-local-mcp-backend.js +288 -0
  282. package/dist/lib/repo-local-mcp-backend.js.map +1 -0
  283. package/dist/lib/repo-local-mcp-runtime.d.ts +17 -0
  284. package/dist/lib/repo-local-mcp-runtime.d.ts.map +1 -0
  285. package/dist/lib/repo-local-mcp-runtime.js +136 -0
  286. package/dist/lib/repo-local-mcp-runtime.js.map +1 -0
  287. package/dist/lib/repo-scope-migration.d.ts +4 -0
  288. package/dist/lib/repo-scope-migration.d.ts.map +1 -0
  289. package/dist/lib/repo-scope-migration.js +55 -0
  290. package/dist/lib/repo-scope-migration.js.map +1 -0
  291. package/dist/lib/repo-scope.d.ts +9 -0
  292. package/dist/lib/repo-scope.d.ts.map +1 -0
  293. package/dist/lib/repo-scope.js +15 -0
  294. package/dist/lib/repo-scope.js.map +1 -0
  295. package/dist/lib/safe-file.d.ts +141 -0
  296. package/dist/lib/safe-file.d.ts.map +1 -0
  297. package/dist/lib/safe-file.js +296 -0
  298. package/dist/lib/safe-file.js.map +1 -0
  299. package/dist/lib/selfhosted-lifecycle.d.ts +78 -0
  300. package/dist/lib/selfhosted-lifecycle.d.ts.map +1 -0
  301. package/dist/lib/selfhosted-lifecycle.js +195 -0
  302. package/dist/lib/selfhosted-lifecycle.js.map +1 -0
  303. package/dist/lib/setup-console.d.ts +1 -1
  304. package/dist/lib/setup-console.d.ts.map +1 -1
  305. package/dist/lib/setup-console.js +3 -1
  306. package/dist/lib/setup-console.js.map +1 -1
  307. package/dist/lib/setup-page.d.ts.map +1 -1
  308. package/dist/lib/setup-page.js +28 -10
  309. package/dist/lib/setup-page.js.map +1 -1
  310. package/dist/lib/setup-plan.d.ts +4 -1
  311. package/dist/lib/setup-plan.d.ts.map +1 -1
  312. package/dist/lib/setup-plan.js +10 -2
  313. package/dist/lib/setup-plan.js.map +1 -1
  314. package/dist/lib/setup-server.d.ts.map +1 -1
  315. package/dist/lib/setup-server.js +19 -3
  316. package/dist/lib/setup-server.js.map +1 -1
  317. package/dist/lib/sso-login.d.ts +42 -0
  318. package/dist/lib/sso-login.d.ts.map +1 -0
  319. package/dist/lib/sso-login.js +135 -0
  320. package/dist/lib/sso-login.js.map +1 -0
  321. package/dist/lib/transfer.d.ts +80 -0
  322. package/dist/lib/transfer.d.ts.map +1 -0
  323. package/dist/lib/transfer.js +173 -0
  324. package/dist/lib/transfer.js.map +1 -0
  325. package/dist/lib/tui.d.ts +0 -6
  326. package/dist/lib/tui.d.ts.map +1 -1
  327. package/dist/lib/tui.js +6 -1
  328. package/dist/lib/tui.js.map +1 -1
  329. package/dist/lib/ui.js +1 -1
  330. package/dist/lib/ui.js.map +1 -1
  331. package/dist/lib/up-result.d.ts +46 -0
  332. package/dist/lib/up-result.d.ts.map +1 -0
  333. package/dist/lib/up-result.js +25 -0
  334. package/dist/lib/up-result.js.map +1 -0
  335. package/dist/menu/run.d.ts +7 -0
  336. package/dist/menu/run.d.ts.map +1 -1
  337. package/dist/menu/run.js +38 -2
  338. package/dist/menu/run.js.map +1 -1
  339. package/oclif.manifest.json +3585 -1532
  340. package/package.json +19 -13
@@ -4,13 +4,17 @@ import { registerSecret, getPlatformDefaultProvider, setPlatformDefaultProvider,
4
4
  import { applyPlatform, resolvePackagedAssetsDir, } from './platform-lifecycle.js';
5
5
  import { parseEnv, redactPlatformSecrets, } from './platform-runtime.js';
6
6
  import { resolveProviderSelection, } from './platform-provider-prompt.js';
7
- import { acquireGhcrLogin, resolveImageSource } from './platform-image-source.js';
7
+ import { acquireGhcrLogin, detectRepoCheckout, resolveImageSource } from './platform-image-source.js';
8
+ import { resolveEditionIntent, shouldUseSelfHostedEdition } from './platform-edition.js';
9
+ import { STABLE_SELFHOSTED_RELEASE, applySelfHosted, resolvePackagedSelfHostedAssetsDir, selfHostedToPlatformResult, } from './selfhosted-lifecycle.js';
8
10
  import { runOnboarding, runOnboardingProviderProbe, waitForOnboardingReady, DEFAULT_LOCAL_PROFILE, } from './platform-onboarding.js';
9
11
  import { ensureEngineReady as ensureContainerEngineReady, } from './container-engine.js';
10
12
  import { withSpinner } from './ui.js';
11
13
  import { buildRegistryLoginInvocation } from './platform-image-source.js';
12
- import { parsePlatformReleaseManifest, PlatformReleaseCatalogHttpError, resolvePlatformRelease, SelfServeResolutionError, } from './platform-release-manifest.js';
14
+ import { parsePlatformReleaseManifest, PlatformReleaseCatalogHttpError, releaseFreshnessNotice, resolvePlatformRelease, SelfServeResolutionError, } from './platform-release-manifest.js';
13
15
  import { normalizeMothershipOrigin, } from './activate.js';
16
+ import { AGE_ELIGIBILITY_TEXT, AGE_ELIGIBILITY_UNDER_13_MESSAGE } from './login.js';
17
+ import { KnowzError, ExitCode } from '@knowzai/core';
14
18
  /**
15
19
  * `knowz up` front-door orchestration — the opinionated one-command onboarding
16
20
  * that composes the AI-provider picker (N1) → image-source resolution (N2) →
@@ -26,9 +30,28 @@ import { normalizeMothershipOrigin, } from './activate.js';
26
30
  * `platform up` (which fails closed without `--version`), `knowz up` supplies a
27
31
  * concrete, deliberately-bumped version so a first-time user gets a working
28
32
  * stack — NEVER a floating tag like `latest`. Override with `--version`.
33
+ *
34
+ * §2026-08-31 R3: this pin MUST equal the newest entry in the packaged
35
+ * `assets/portable/releases.json` (exact semver equality — enforced by the
36
+ * up.test.ts anti-rot tripwire). The /release-platform skill bumps BOTH in the
37
+ * same release commit; bump one without the other and the tripwire goes red.
29
38
  */
30
- export const STABLE_PORTABLE_RELEASE = '0.35.2';
39
+ export const STABLE_PORTABLE_RELEASE = '0.41.0';
31
40
  export const DEFAULT_PORTABLE_VERSION = STABLE_PORTABLE_RELEASE;
41
+ const DEFAULT_INSTANCE_NAME = 'knowz';
42
+ /**
43
+ * Per-instance CLI profile derivation (smoke gap 1, lead ruling): the default
44
+ * instance keeps the back-compat `local` profile; a named instance gets
45
+ * `local-<name>` so a second instance's `up` can never silently repoint the
46
+ * first instance's profile. Shared by terminal `up` and the setup console
47
+ * (`setupPlanToFrontDoorInput`) so both front-ends derive identically.
48
+ */
49
+ export function localProfileNameFor(instanceName) {
50
+ const name = instanceName?.trim();
51
+ return !name || name === DEFAULT_INSTANCE_NAME
52
+ ? DEFAULT_LOCAL_PROFILE
53
+ : `${DEFAULT_LOCAL_PROFILE}-${name}`;
54
+ }
32
55
  export function resolveDefaultPortableVersion(env) {
33
56
  const value = env.KNOWZ_PLATFORM_VERSION?.trim();
34
57
  if (!value)
@@ -72,6 +95,31 @@ function e5() {
72
95
  function activationRequired() {
73
96
  return new SelfServeResolutionError("This device is not linked to a Knowz account. Run 'knowz activate' in an interactive terminal, then retry 'knowz up --json'.", 'ACTIVATION_REQUIRED');
74
97
  }
98
+ const LICENSE_REQUIRED_FALLBACK = 'This installation does not have an active platform license. Complete registration and your commercial agreement to enable image pulls.';
99
+ const LICENSE_REQUIRED_REMEDIATION = 'Request a portable license from Settings → Installations on your Knowz account, or see https://knowz.io/pricing.';
100
+ const PROBLEM_DETAIL_MAX_LENGTH = 500;
101
+ function licenseRequiredError(preflight) {
102
+ const detail = sanitizeProblemDetail(preflight.detail);
103
+ return new SelfServeResolutionError(`${detail ?? LICENSE_REQUIRED_FALLBACK} ${LICENSE_REQUIRED_REMEDIATION}`, 'LICENSE_REQUIRED');
104
+ }
105
+ function sanitizeProblemDetail(detail) {
106
+ if (typeof detail !== 'string' || detail.length === 0)
107
+ return undefined;
108
+ const stripped = stripC0AndCsi(detail).trim();
109
+ if (!stripped)
110
+ return undefined;
111
+ return stripped.length > PROBLEM_DETAIL_MAX_LENGTH
112
+ ? stripped.slice(0, PROBLEM_DETAIL_MAX_LENGTH)
113
+ : stripped;
114
+ }
115
+ function stripC0AndCsi(value) {
116
+ return value
117
+ .replace(/\u001b\[[0-9;?]*[ -/]*[@-~]/g, '')
118
+ .replace(/\u009b[0-9;?]*[ -/]*[@-~]/g, '')
119
+ .replace(/\u001b\][^\u0007\u001b]*(?:\u0007|\u001b\\)/g, '')
120
+ .replace(/\u001b[@-Z\\-_]/g, '')
121
+ .replace(/[\u0000-\u001f\u007f-\u009f]/g, '');
122
+ }
75
123
  async function defaultFetchReleaseManifest(url) {
76
124
  const response = await fetch(url, {
77
125
  headers: { accept: 'application/json' },
@@ -81,6 +129,63 @@ async function defaultFetchReleaseManifest(url) {
81
129
  throw new PlatformReleaseCatalogHttpError(response.status);
82
130
  return response.json();
83
131
  }
132
+ /** §2026-08-31 R4 (lead ruling): the advisory fetch is bounded to 2s — never slower. */
133
+ const ADVISORY_MANIFEST_TIMEOUT_MS = 2_000;
134
+ async function withAdvisoryTimeout(work) {
135
+ let timer;
136
+ try {
137
+ return await Promise.race([
138
+ work,
139
+ new Promise((_, reject) => {
140
+ timer = setTimeout(() => reject(new Error('Advisory release-manifest fetch timed out.')), ADVISORY_MANIFEST_TIMEOUT_MS);
141
+ }),
142
+ ]);
143
+ }
144
+ finally {
145
+ if (timer !== undefined)
146
+ clearTimeout(timer);
147
+ }
148
+ }
149
+ /**
150
+ * §2026-08-31 R4: ADVISORY manifest load for the ghcr-token / preloaded paths —
151
+ * bounded fetch, packaged-copy fallback, and ANY failure returns undefined.
152
+ * Freshness must never block, slow (beyond the bound), or error an air-gapped
153
+ * boot. Requires the injected `fetchReleaseManifest` (the real runtime always
154
+ * binds it); when absent the advisory silently does not run, keeping legacy
155
+ * injected embedders/tests byte-identical and network-free.
156
+ */
157
+ async function loadAdvisoryReleaseManifest(input) {
158
+ try {
159
+ const raw = await withAdvisoryTimeout(input.fetchReleaseManifest(input.manifestUrl));
160
+ return parsePlatformReleaseManifest(raw);
161
+ }
162
+ catch {
163
+ // Fall through to the packaged copy — advisory failures are silent by contract.
164
+ }
165
+ try {
166
+ const fallback = input.loadPackagedReleaseManifest
167
+ ? await input.loadPackagedReleaseManifest(input.packagedManifestPath)
168
+ : JSON.parse(readFileSync(input.packagedManifestPath, 'utf8'));
169
+ return parsePlatformReleaseManifest(fallback);
170
+ }
171
+ catch {
172
+ return undefined;
173
+ }
174
+ }
175
+ /**
176
+ * §2026-08-31 R-N2: static reference-only next-steps epilogue after a fresh
177
+ * successful `knowz up`. Copy mirrors the setup-console success panel (R-N1);
178
+ * the commands are defined by CLI_PortabilityTransfer / CLI_InstanceTransfer.
179
+ * Routed through the injectable sink — `--json` runs and the setup console
180
+ * (which forces `input.json`) never see these lines, and `loginMode:'existing'`
181
+ * re-ups skip the call entirely.
182
+ */
183
+ function emitNextSteps(log) {
184
+ log('Next steps:');
185
+ log(' Connect this instance to Knowz Cloud: knowz login --profile cloud');
186
+ log(' Move data between instances: knowz transfer --from <profile> --to <profile>');
187
+ log(' Snapshot / restore: knowz export / knowz import');
188
+ }
84
189
  export async function runFrontDoor(input, deps) {
85
190
  const log = input.json
86
191
  ? (_line) => { }
@@ -142,14 +247,29 @@ export async function runFrontDoor(input, deps) {
142
247
  if (requestedSuperAdminPassphrase)
143
248
  registerSecret(requestedSuperAdminPassphrase);
144
249
  let identity = input.identity;
145
- if (!identity && interactivePromptOccurred) {
146
- const name = (await deps.prompt.text({ message: 'First account name:', default: 'Local' })).trim();
147
- const email = (await deps.prompt.text({ message: 'First account email:', default: 'local@knowz.local' })).trim();
148
- identity = {
250
+ const collectRegistrationIdentity = async () => {
251
+ if (identity?.ageAttested === true)
252
+ return identity;
253
+ if (!canPrompt) {
254
+ if (identity) {
255
+ throw new KnowzError('Age eligibility is never assumed. Pass --age-13-plus to confirm eligibility before registration.', ExitCode.Usage);
256
+ }
257
+ return identity;
258
+ }
259
+ const ageAttested = await deps.prompt.confirm?.({ message: AGE_ELIGIBILITY_TEXT, default: false }) ?? false;
260
+ if (!ageAttested)
261
+ throw new KnowzError(AGE_ELIGIBILITY_UNDER_13_MESSAGE, ExitCode.Usage);
262
+ const name = identity?.name ?? (await deps.prompt.text({ message: 'First account name:', default: 'Local' })).trim();
263
+ const email = identity?.email ?? (await deps.prompt.text({ message: 'First account email:', default: 'local@knowz.local' })).trim();
264
+ return {
149
265
  name: name || 'Local',
150
266
  email: email || 'local@knowz.local',
267
+ // `as const` so the literal is not widened to `boolean`: `identity` is
268
+ // typed `ageAttested?: true`, and attestation is deliberately a one-way
269
+ // flag — there is no "attested: false" state, only an absent one.
270
+ ageAttested: true,
151
271
  };
152
- }
272
+ };
153
273
  // Discoverability: when a saved default was silently reused (no --offline/--ai/--provider,
154
274
  // where --provider folds into providerFlags.ai), explain why no prompt appeared.
155
275
  if (cfgDefault && !interactivePromptOccurred && !input.providerFlags.offline && !input.providerFlags.ai) {
@@ -164,23 +284,76 @@ export async function runFrontDoor(input, deps) {
164
284
  axes: selection.axes ?? input.base.axes,
165
285
  superAdminPassphrase: requestedSuperAdminPassphrase,
166
286
  };
167
- // 2) Image source: build-from-checkout runs in place at the repo root; pull keeps
168
- // the byte-identical copy-into-runtime-dir seam (so we only override the plan).
169
- const source = resolveImageSource({
170
- cwd: deps.cwd,
171
- flags: input.imageFlags,
172
- canPrompt: deps.isTty && Boolean(deps.ghcrPrompt),
173
- pathExists: deps.pathExists,
174
- packagedAssetsDir: deps.packagedAssetsDir,
175
- env: input.ghcrToken
176
- ? { ...deps.env, GHCR_PULL_TOKEN: input.ghcrToken }
177
- : deps.env,
287
+ // 2) Edition then image source. Unentitled `knowz up` uses public selfhosted
288
+ // images; the portable resolver is unchanged when edition is portable.
289
+ const envForEdition = input.ghcrToken
290
+ ? { ...deps.env, GHCR_PULL_TOKEN: input.ghcrToken }
291
+ : deps.env;
292
+ const editionIntent = resolveEditionIntent({
293
+ flags: { edition: input.edition },
294
+ env: envForEdition,
295
+ });
296
+ const checkoutDetected = Boolean(detectRepoCheckout(deps.cwd, deps.pathExists));
297
+ let useSelfHosted = shouldUseSelfHostedEdition({
298
+ intent: editionIntent,
299
+ imageFlags: input.imageFlags,
300
+ checkoutDetected,
178
301
  });
302
+ // R-ED3: omitted edition + stored kzin_ may promote to portable after a 200
303
+ // preflight. 403/401/410/transport stay selfhosted and MUST NOT reactivate.
304
+ if (useSelfHosted &&
305
+ !editionIntent.explicit &&
306
+ deps.loadStoredActivation &&
307
+ deps.preflightRegistryCredential) {
308
+ const mothershipUrl = normalizeMothershipOrigin(deps.env.KNOWZ_LICENSING_MOTHERSHIP_URL?.trim() || DEFAULT_MOTHERSHIP_URL);
309
+ try {
310
+ const stored = await deps.loadStoredActivation({
311
+ projectName: input.base.name,
312
+ configDir: input.base.configDir,
313
+ engine: engine ?? LEGACY_DOCKER_ENGINE,
314
+ });
315
+ if (stored) {
316
+ const preflight = await deps.preflightRegistryCredential({
317
+ mothershipUrl,
318
+ activation: stored,
319
+ });
320
+ if (preflight.kind === 'http-response' && preflight.status === 200) {
321
+ useSelfHosted = false;
322
+ }
323
+ else {
324
+ log('Stored installation is not entitled for portable images; using public selfhosted.');
325
+ }
326
+ }
327
+ }
328
+ catch {
329
+ // Default knowz up must not fail because a mothership probe threw.
330
+ }
331
+ }
332
+ const source = useSelfHosted
333
+ ? {
334
+ mode: 'pull',
335
+ composeFile: 'selfhosted',
336
+ projectDir: 'selfhosted',
337
+ composePlan: 'config-pull-up',
338
+ }
339
+ : resolveImageSource({
340
+ cwd: deps.cwd,
341
+ flags: input.imageFlags,
342
+ canPrompt: deps.isTty && Boolean(deps.ghcrPrompt),
343
+ pathExists: deps.pathExists,
344
+ packagedAssetsDir: deps.packagedAssetsDir,
345
+ env: envForEdition,
346
+ });
179
347
  const seam = source.mode === 'build'
180
348
  ? { composeFile: source.composeFile, projectDir: source.projectDir, composePlan: source.composePlan }
181
349
  : source.mode === 'pull'
182
- ? { composePlan: source.composePlan, registry: source.registry ?? null }
350
+ ? { composePlan: source.composePlan, registry: 'registry' in source ? source.registry ?? null : null }
183
351
  : { composePlan: source.composePlan };
352
+ // §2026-08-31 R7: portable images are linux/amd64-only. Selfhosted GHCR is multi-arch.
353
+ const hostArch = deps.hostArch ?? process.arch;
354
+ if (!useSelfHosted && hostArch === 'arm64' && (source.mode === 'pull' || source.mode === 'preloaded')) {
355
+ log('Note: knowz images run under amd64 emulation on this Mac; native arm64 images are not yet published.');
356
+ }
184
357
  const selfServePlan = source.loginPlan?.kind === 'self-serve' ? source.loginPlan : undefined;
185
358
  if (selfServePlan) {
186
359
  const mothershipUrl = normalizeMothershipOrigin(deps.env.KNOWZ_LICENSING_MOTHERSHIP_URL?.trim() || DEFAULT_MOTHERSHIP_URL);
@@ -235,6 +408,41 @@ export async function runFrontDoor(input, deps) {
235
408
  if (resolved.note)
236
409
  log(resolved.note);
237
410
  log(`✓ Knowz Platform ${resolved.release.version} (${flavor}) — released ${resolved.release.releasedAt.slice(0, 10)}`);
411
+ // §2026-08-31 R4 (self-serve): zero new network — reuse the fetched manifest.
412
+ // Fires only for an explicit older pin; a minCliVersion skip already emitted
413
+ // its own note above, and the freshness notice must never duplicate it.
414
+ if (!resolved.note) {
415
+ const freshness = releaseFreshnessNotice({
416
+ currentVersion: resolved.release.version,
417
+ manifest,
418
+ flavor,
419
+ });
420
+ if (freshness)
421
+ log(freshness);
422
+ }
423
+ }
424
+ else if (selection.provider !== 'offline' &&
425
+ (source.mode === 'preloaded' || source.loginPlan?.kind === 'ghcr') &&
426
+ deps.fetchReleaseManifest) {
427
+ // §2026-08-31 R4 (ghcr-token / preloaded): no manifest resolution runs on these
428
+ // paths, so the version about to boot is the pin/explicit choice. Advisory-only
429
+ // freshness check — bounded, fail-silent, and skipped entirely for the offline
430
+ // provider (declared no-network intent, lead ruling on OQ-2).
431
+ const advisoryManifest = await loadAdvisoryReleaseManifest({
432
+ manifestUrl: `${normalizeMothershipOrigin(deps.env.KNOWZ_LICENSING_MOTHERSHIP_URL?.trim() || DEFAULT_MOTHERSHIP_URL)}${RELEASE_MANIFEST_PATH}`,
433
+ packagedManifestPath: join(source.projectDir, 'releases.json'),
434
+ fetchReleaseManifest: deps.fetchReleaseManifest,
435
+ loadPackagedReleaseManifest: deps.loadPackagedReleaseManifest,
436
+ });
437
+ if (advisoryManifest) {
438
+ const freshness = releaseFreshnessNotice({
439
+ currentVersion: applyInput.version ?? DEFAULT_PORTABLE_VERSION,
440
+ manifest: advisoryManifest,
441
+ flavor: selection.provider === 'gcp' ? 'portable-gcp' : 'portable',
442
+ });
443
+ if (freshness)
444
+ log(freshness);
445
+ }
238
446
  }
239
447
  // Advisory credential reachability check. Failure is intentionally warn-only.
240
448
  if (input.validate === true && deps.probeProvider) {
@@ -275,123 +483,146 @@ export async function runFrontDoor(input, deps) {
275
483
  };
276
484
  // 3) Bring the stack up; anonymous pull first, authenticate + retry once on auth failure.
277
485
  let applied;
278
- if (selfServePlan)
279
- log(`◇ Pulling images from ${selfServePlan.registry}…`);
280
- try {
281
- applied = await (deps.applyPlatform ?? applyPlatform)(applyInput, applyDeps, seam);
282
- if (selfServePlan)
283
- log(`◇ Pulling images from ${selfServePlan.registry}… ✓`);
486
+ if (useSelfHosted) {
487
+ log('Using public selfhosted images. Portable platform requires --edition=portable and an entitled key.');
488
+ const selfhostedVersion = input.versionExplicit && applyInput.version
489
+ ? applyInput.version
490
+ : (deps.env.KNOWZ_SELFHOSTED_VERSION?.trim() || STABLE_SELFHOSTED_RELEASE);
491
+ const selfhosted = applySelfHosted({
492
+ name: input.base.name,
493
+ version: selfhostedVersion,
494
+ configDir: input.base.configDir,
495
+ ports,
496
+ }, {
497
+ runner: deps.runner,
498
+ randomBytes: deps.randomBytes,
499
+ packagedAssetsDir: deps.selfHostedAssetsDir ?? resolvePackagedSelfHostedAssetsDir(),
500
+ });
501
+ applied = selfHostedToPlatformResult(selfhosted, selection.provider, deps.now);
284
502
  }
285
- catch (error) {
286
- if (source.mode === 'pull' &&
287
- source.loginPlan?.kind === 'ghcr' &&
288
- isRegistryAuthError(error)) {
289
- const loginEnv = input.ghcrToken
290
- ? { ...deps.env, GHCR_PULL_TOKEN: input.ghcrToken }
291
- : deps.env;
292
- const login = await acquireGhcrLogin(source.loginPlan, deps.ghcrPrompt, loginEnv);
293
- if (!login)
294
- throw error;
295
- log('Registry rejected an anonymous pull; authenticating and retrying…');
296
- applied = await (deps.applyPlatform ?? applyPlatform)(applyInput, applyDeps, { ...seam, login });
503
+ else {
504
+ if (selfServePlan)
505
+ log(`◇ Pulling images from ${selfServePlan.registry}…`);
506
+ try {
507
+ applied = await (deps.applyPlatform ?? applyPlatform)(applyInput, applyDeps, seam);
508
+ if (selfServePlan)
509
+ log(`◇ Pulling images from ${selfServePlan.registry}… ✓`);
297
510
  }
298
- else if (source.mode === 'pull' && selfServePlan && isRegistryAuthError(error)) {
299
- const activeEngine = engine ?? LEGACY_DOCKER_ENGINE;
300
- const mothershipUrl = normalizeMothershipOrigin(deps.env.KNOWZ_LICENSING_MOTHERSHIP_URL?.trim() || DEFAULT_MOTHERSHIP_URL);
301
- if (!deps.loadStoredActivation ||
302
- !deps.activateInstallation ||
303
- !deps.preflightRegistryCredential) {
304
- throw new Error('Self-serve registry authentication dependencies are not configured.');
511
+ catch (error) {
512
+ if (source.mode === 'pull' &&
513
+ source.loginPlan?.kind === 'ghcr' &&
514
+ isRegistryAuthError(error)) {
515
+ const loginEnv = input.ghcrToken
516
+ ? { ...deps.env, GHCR_PULL_TOKEN: input.ghcrToken }
517
+ : deps.env;
518
+ const login = await acquireGhcrLogin(source.loginPlan, deps.ghcrPrompt, loginEnv);
519
+ if (!login)
520
+ throw error;
521
+ log('Registry rejected an anonymous pull; authenticating and retrying…');
522
+ applied = await (deps.applyPlatform ?? applyPlatform)(applyInput, applyDeps, { ...seam, login });
305
523
  }
306
- let activation = await deps.loadStoredActivation({
307
- projectName: input.base.name,
308
- configDir: input.base.configDir,
309
- engine: activeEngine,
310
- });
311
- let activatedNow = false;
312
- if (!activation) {
313
- if (input.json)
314
- throw activationRequired();
315
- log("This device isn't linked to a Knowz account yet.");
316
- log('Linking is free and takes about a minute — your browser will open so you can approve this device.');
317
- log('');
318
- try {
319
- activation = await deps.activateInstallation({
320
- projectName: input.base.name,
321
- configDir: input.base.configDir,
322
- mothershipUrl,
323
- engine: activeEngine,
324
- });
325
- activatedNow = true;
524
+ else if (source.mode === 'pull' && selfServePlan && isRegistryAuthError(error)) {
525
+ const activeEngine = engine ?? LEGACY_DOCKER_ENGINE;
526
+ const mothershipUrl = normalizeMothershipOrigin(deps.env.KNOWZ_LICENSING_MOTHERSHIP_URL?.trim() || DEFAULT_MOTHERSHIP_URL);
527
+ if (!deps.loadStoredActivation ||
528
+ !deps.activateInstallation ||
529
+ !deps.preflightRegistryCredential) {
530
+ throw new Error('Self-serve registry authentication dependencies are not configured.');
326
531
  }
327
- catch {
328
- throw e5();
329
- }
330
- }
331
- let preflight = await deps.preflightRegistryCredential({ mothershipUrl, activation });
332
- if (preflight.kind === 'transport-failure') {
333
- throw new SelfServeResolutionError(`Could not reach the Knowz image authorization service at ${mothershipUrl}/api/v1/registry/token. ` +
334
- 'Check your network connection, then retry.', 'REGISTRY_AUTH_UNREACHABLE');
335
- }
336
- let preflightStatus = preflight.status;
337
- if (preflightStatus === 410)
338
- throw e4(activation.installationId);
339
- if (preflightStatus === 401) {
340
- if (activatedNow || !canPrompt || !deps.confirmReactivation) {
341
- throw new SelfServeResolutionError(`Stored installation ${activation.installationId} is no longer valid. Run 'knowz activate' to link this device again.`, 'INSTALLATION_INVALID');
342
- }
343
- const accepted = await deps.confirmReactivation(activation.installationId);
344
- if (!accepted)
345
- throw e5();
346
- try {
347
- activation = await deps.activateInstallation({
348
- projectName: input.base.name,
349
- configDir: input.base.configDir,
350
- mothershipUrl,
351
- engine: activeEngine,
352
- });
353
- activatedNow = true;
354
- }
355
- catch {
356
- throw e5();
532
+ let activation = await deps.loadStoredActivation({
533
+ projectName: input.base.name,
534
+ configDir: input.base.configDir,
535
+ engine: activeEngine,
536
+ });
537
+ let activatedNow = false;
538
+ if (!activation) {
539
+ if (input.json)
540
+ throw activationRequired();
541
+ log("This device isn't linked to a Knowz account yet.");
542
+ log('Linking is free and takes about a minute — your browser will open so you can approve this device.');
543
+ log('');
544
+ try {
545
+ activation = await deps.activateInstallation({
546
+ projectName: input.base.name,
547
+ configDir: input.base.configDir,
548
+ mothershipUrl,
549
+ engine: activeEngine,
550
+ });
551
+ activatedNow = true;
552
+ }
553
+ catch {
554
+ throw e5();
555
+ }
357
556
  }
358
- preflight = await deps.preflightRegistryCredential({ mothershipUrl, activation });
557
+ let preflight = await deps.preflightRegistryCredential({ mothershipUrl, activation });
359
558
  if (preflight.kind === 'transport-failure') {
360
559
  throw new SelfServeResolutionError(`Could not reach the Knowz image authorization service at ${mothershipUrl}/api/v1/registry/token. ` +
361
560
  'Check your network connection, then retry.', 'REGISTRY_AUTH_UNREACHABLE');
362
561
  }
363
- preflightStatus = preflight.status;
562
+ let preflightStatus = preflight.status;
563
+ if (preflightStatus === 403)
564
+ throw licenseRequiredError(preflight);
364
565
  if (preflightStatus === 410)
365
566
  throw e4(activation.installationId);
567
+ if (preflightStatus === 401) {
568
+ if (activatedNow || !canPrompt || !deps.confirmReactivation) {
569
+ throw new SelfServeResolutionError(`Stored installation ${activation.installationId} is no longer valid. Run 'knowz activate' to link this device again.`, 'INSTALLATION_INVALID');
570
+ }
571
+ const accepted = await deps.confirmReactivation(activation.installationId);
572
+ if (!accepted)
573
+ throw e5();
574
+ try {
575
+ activation = await deps.activateInstallation({
576
+ projectName: input.base.name,
577
+ configDir: input.base.configDir,
578
+ mothershipUrl,
579
+ engine: activeEngine,
580
+ });
581
+ activatedNow = true;
582
+ }
583
+ catch {
584
+ throw e5();
585
+ }
586
+ preflight = await deps.preflightRegistryCredential({ mothershipUrl, activation });
587
+ if (preflight.kind === 'transport-failure') {
588
+ throw new SelfServeResolutionError(`Could not reach the Knowz image authorization service at ${mothershipUrl}/api/v1/registry/token. ` +
589
+ 'Check your network connection, then retry.', 'REGISTRY_AUTH_UNREACHABLE');
590
+ }
591
+ preflightStatus = preflight.status;
592
+ if (preflightStatus === 403)
593
+ throw licenseRequiredError(preflight);
594
+ if (preflightStatus === 410)
595
+ throw e4(activation.installationId);
596
+ }
597
+ if (preflightStatus !== 200) {
598
+ throw new SelfServeResolutionError(`Knowz could not authorize installation ${activation.installationId} for image pulls (HTTP ${preflightStatus}).`, 'INSTALLATION_INVALID');
599
+ }
600
+ registerSecret(activation.credential);
601
+ if (activatedNow)
602
+ log(`✓ Linked — installation "${input.base.name}"`);
603
+ const login = buildRegistryLoginInvocation(selfServePlan.registry, activation.installationId, activation.credential);
604
+ try {
605
+ applied = await (deps.applyPlatform ?? applyPlatform)(applyInput, applyDeps, {
606
+ ...seam,
607
+ login,
608
+ });
609
+ }
610
+ catch (retryError) {
611
+ throw new SelfServeResolutionError('Knowz could not pull the published platform images after signing in. The container engine reported: ' +
612
+ redactPlatformSecrets(errorMessage(retryError), [activation.credential]), 'REGISTRY_PULL_FAILED');
613
+ }
614
+ log(`◇ Signing in to ${selfServePlan.registry}… ✓`);
615
+ log(`◇ Pulling images from ${selfServePlan.registry}… ✓`);
366
616
  }
367
- if (preflightStatus !== 200) {
368
- throw new SelfServeResolutionError(`Knowz could not authorize installation ${activation.installationId} for image pulls (HTTP ${preflightStatus}).`, 'INSTALLATION_INVALID');
369
- }
370
- registerSecret(activation.credential);
371
- if (activatedNow)
372
- log(`✓ Linked — installation "${input.base.name}"`);
373
- const login = buildRegistryLoginInvocation(selfServePlan.registry, activation.installationId, activation.credential);
374
- try {
375
- applied = await (deps.applyPlatform ?? applyPlatform)(applyInput, applyDeps, {
376
- ...seam,
377
- login,
378
- });
617
+ else if (source.mode === 'pull' &&
618
+ source.registry &&
619
+ !source.loginPlan &&
620
+ isRegistryAuthError(error)) {
621
+ throw new Error(`Registry override ${source.registry} refused image access: ${errorMessage(error)}`);
379
622
  }
380
- catch (retryError) {
381
- throw new SelfServeResolutionError('Knowz could not pull the published platform images after signing in. The container engine reported: ' +
382
- redactPlatformSecrets(errorMessage(retryError), [activation.credential]), 'REGISTRY_PULL_FAILED');
623
+ else {
624
+ throw error;
383
625
  }
384
- log(`◇ Signing in to ${selfServePlan.registry}… ✓`);
385
- log(`◇ Pulling images from ${selfServePlan.registry}… ✓`);
386
- }
387
- else if (source.mode === 'pull' &&
388
- source.registry &&
389
- !source.loginPlan &&
390
- isRegistryAuthError(error)) {
391
- throw new Error(`Registry override ${source.registry} refused image access: ${errorMessage(error)}`);
392
- }
393
- else {
394
- throw error;
395
626
  }
396
627
  }
397
628
  for (const line of applied.output.split('\n'))
@@ -421,7 +652,9 @@ export async function runFrontDoor(input, deps) {
421
652
  // profile reuse. Passing the result into onboarding avoids a second poll.
422
653
  const apiReady = await waitForOnboardingReady({}, onboardingDeps);
423
654
  if (!apiReady) {
424
- const onboarding = await runOnboarding({ ...onboardingInput, apiReady }, onboardingDeps);
655
+ identity = await collectRegistrationIdentity();
656
+ const onboarding = await runOnboarding({ ...onboardingInput, register: identity, apiReady }, onboardingDeps);
657
+ emitNextSteps(log);
425
658
  return {
426
659
  state: applied.state,
427
660
  imageMode: source.mode,
@@ -429,6 +662,7 @@ export async function runFrontDoor(input, deps) {
429
662
  profile: onboarding.profile ?? null,
430
663
  loginMode: onboarding.loginMode,
431
664
  seeded: onboarding.seeded,
665
+ edition: useSelfHosted ? 'selfhosted' : 'portable',
432
666
  };
433
667
  }
434
668
  // 4b) If a prior `up` already signed the CLI profile in and its key still authenticates,
@@ -442,10 +676,12 @@ export async function runFrontDoor(input, deps) {
442
676
  log(` API: ${apiUrl}`);
443
677
  if (input.open)
444
678
  onboardingDeps.openBrowser(webUrl);
445
- return { state: applied.state, imageMode: source.mode, provider: selection.provider, profile: profileName, loginMode: 'existing', seeded: false };
679
+ return { state: applied.state, imageMode: source.mode, provider: selection.provider, profile: profileName, loginMode: 'existing', seeded: false, edition: useSelfHosted ? 'selfhosted' : 'portable' };
446
680
  }
447
681
  // 4c) Onboarding: bootstrap → register fallback → manual degrade.
448
- const onboarding = await runOnboarding({ ...onboardingInput, apiReady }, onboardingDeps);
682
+ identity = await collectRegistrationIdentity();
683
+ const onboarding = await runOnboarding({ ...onboardingInput, register: identity, apiReady }, onboardingDeps);
684
+ emitNextSteps(log);
449
685
  return {
450
686
  state: applied.state,
451
687
  imageMode: source.mode,
@@ -453,6 +689,7 @@ export async function runFrontDoor(input, deps) {
453
689
  profile: onboarding.profile ?? null,
454
690
  loginMode: onboarding.loginMode,
455
691
  seeded: onboarding.seeded,
692
+ edition: useSelfHosted ? 'selfhosted' : 'portable',
456
693
  };
457
694
  }
458
695
  /** Read the packaged runtime contract's `providerPresets.{preset}.requiredEnvironment` map (drift-fenced source). */