@osva-ai/cli 1.1.1 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/README.md +36 -0
  2. package/dist/bin/osva.js +26 -0
  3. package/dist/bin/osva.js.map +1 -1
  4. package/dist/commands/index.js +6 -0
  5. package/dist/commands/index.js.map +1 -1
  6. package/dist/doctor/redact.d.ts.map +1 -1
  7. package/dist/doctor/redact.js +3 -1
  8. package/dist/doctor/redact.js.map +1 -1
  9. package/dist/doctor/run-doctor.d.ts +2 -1
  10. package/dist/doctor/run-doctor.d.ts.map +1 -1
  11. package/dist/doctor/run-doctor.js +1 -1
  12. package/dist/doctor/run-doctor.js.map +1 -1
  13. package/dist/doctor/streaming-redact.d.ts +11 -0
  14. package/dist/doctor/streaming-redact.d.ts.map +1 -0
  15. package/dist/doctor/streaming-redact.js +29 -0
  16. package/dist/doctor/streaming-redact.js.map +1 -0
  17. package/dist/platform/compose-inspect.d.ts +9 -0
  18. package/dist/platform/compose-inspect.d.ts.map +1 -0
  19. package/dist/platform/compose-inspect.js +114 -0
  20. package/dist/platform/compose-inspect.js.map +1 -0
  21. package/dist/platform/doctor.d.ts +10 -0
  22. package/dist/platform/doctor.d.ts.map +1 -0
  23. package/dist/platform/doctor.js +154 -0
  24. package/dist/platform/doctor.js.map +1 -0
  25. package/dist/platform/format.d.ts +10 -0
  26. package/dist/platform/format.d.ts.map +1 -0
  27. package/dist/platform/format.js +73 -0
  28. package/dist/platform/format.js.map +1 -0
  29. package/dist/platform/index.d.ts +9 -0
  30. package/dist/platform/index.d.ts.map +1 -0
  31. package/dist/platform/index.js +143 -0
  32. package/dist/platform/index.js.map +1 -0
  33. package/dist/platform/lifecycle.d.ts +20 -0
  34. package/dist/platform/lifecycle.d.ts.map +1 -0
  35. package/dist/platform/lifecycle.js +136 -0
  36. package/dist/platform/lifecycle.js.map +1 -0
  37. package/dist/platform/logs.d.ts +12 -0
  38. package/dist/platform/logs.d.ts.map +1 -0
  39. package/dist/platform/logs.js +81 -0
  40. package/dist/platform/logs.js.map +1 -0
  41. package/dist/platform/readiness.d.ts +9 -0
  42. package/dist/platform/readiness.d.ts.map +1 -0
  43. package/dist/platform/readiness.js +58 -0
  44. package/dist/platform/readiness.js.map +1 -0
  45. package/dist/platform/resolve-installation.d.ts +5 -0
  46. package/dist/platform/resolve-installation.d.ts.map +1 -0
  47. package/dist/platform/resolve-installation.js +115 -0
  48. package/dist/platform/resolve-installation.js.map +1 -0
  49. package/dist/platform/services.d.ts +7 -0
  50. package/dist/platform/services.d.ts.map +1 -0
  51. package/dist/platform/services.js +21 -0
  52. package/dist/platform/services.js.map +1 -0
  53. package/dist/platform/status.d.ts +7 -0
  54. package/dist/platform/status.d.ts.map +1 -0
  55. package/dist/platform/status.js +60 -0
  56. package/dist/platform/status.js.map +1 -0
  57. package/dist/platform/types.d.ts +37 -0
  58. package/dist/platform/types.d.ts.map +1 -0
  59. package/dist/platform/types.js +8 -0
  60. package/dist/platform/types.js.map +1 -0
  61. package/dist/platform/upgrade/backup-policy.d.ts +4 -0
  62. package/dist/platform/upgrade/backup-policy.d.ts.map +1 -0
  63. package/dist/platform/upgrade/backup-policy.js +20 -0
  64. package/dist/platform/upgrade/backup-policy.js.map +1 -0
  65. package/dist/platform/upgrade/catalog.d.ts +26 -0
  66. package/dist/platform/upgrade/catalog.d.ts.map +1 -0
  67. package/dist/platform/upgrade/catalog.js +56 -0
  68. package/dist/platform/upgrade/catalog.js.map +1 -0
  69. package/dist/platform/upgrade/options.d.ts +8 -0
  70. package/dist/platform/upgrade/options.d.ts.map +1 -0
  71. package/dist/platform/upgrade/options.js +17 -0
  72. package/dist/platform/upgrade/options.js.map +1 -0
  73. package/dist/platform/upgrade/preflight.d.ts +25 -0
  74. package/dist/platform/upgrade/preflight.d.ts.map +1 -0
  75. package/dist/platform/upgrade/preflight.js +91 -0
  76. package/dist/platform/upgrade/preflight.js.map +1 -0
  77. package/dist/platform/upgrade/run-upgrade.d.ts +22 -0
  78. package/dist/platform/upgrade/run-upgrade.d.ts.map +1 -0
  79. package/dist/platform/upgrade/run-upgrade.js +253 -0
  80. package/dist/platform/upgrade/run-upgrade.js.map +1 -0
  81. package/dist/platform/upgrade/state.d.ts +31 -0
  82. package/dist/platform/upgrade/state.d.ts.map +1 -0
  83. package/dist/platform/upgrade/state.js +129 -0
  84. package/dist/platform/upgrade/state.js.map +1 -0
  85. package/dist/platform/upgrade/version.d.ts +11 -0
  86. package/dist/platform/upgrade/version.d.ts.map +1 -0
  87. package/dist/platform/upgrade/version.js +70 -0
  88. package/dist/platform/upgrade/version.js.map +1 -0
  89. package/dist/platform/upgrade-guard.d.ts +2 -0
  90. package/dist/platform/upgrade-guard.d.ts.map +1 -0
  91. package/dist/platform/upgrade-guard.js +12 -0
  92. package/dist/platform/upgrade-guard.js.map +1 -0
  93. package/dist/setup/acceptance-install.d.ts +15 -0
  94. package/dist/setup/acceptance-install.d.ts.map +1 -0
  95. package/dist/setup/acceptance-install.js +44 -0
  96. package/dist/setup/acceptance-install.js.map +1 -0
  97. package/dist/setup/atomic-write.d.ts +4 -0
  98. package/dist/setup/atomic-write.d.ts.map +1 -0
  99. package/dist/setup/atomic-write.js +19 -0
  100. package/dist/setup/atomic-write.js.map +1 -0
  101. package/dist/setup/bootstrap-capture.d.ts +9 -0
  102. package/dist/setup/bootstrap-capture.d.ts.map +1 -0
  103. package/dist/setup/bootstrap-capture.js +64 -0
  104. package/dist/setup/bootstrap-capture.js.map +1 -0
  105. package/dist/setup/compose-exec.d.ts +21 -0
  106. package/dist/setup/compose-exec.d.ts.map +1 -0
  107. package/dist/setup/compose-exec.js +55 -0
  108. package/dist/setup/compose-exec.js.map +1 -0
  109. package/dist/setup/compose-project.d.ts +3 -0
  110. package/dist/setup/compose-project.d.ts.map +1 -0
  111. package/dist/setup/compose-project.js +12 -0
  112. package/dist/setup/compose-project.js.map +1 -0
  113. package/dist/setup/compose-template-root.d.ts +3 -0
  114. package/dist/setup/compose-template-root.d.ts.map +1 -0
  115. package/dist/setup/compose-template-root.js +8 -0
  116. package/dist/setup/compose-template-root.js.map +1 -0
  117. package/dist/setup/distribution.d.ts +13 -0
  118. package/dist/setup/distribution.d.ts.map +1 -0
  119. package/dist/setup/distribution.js +55 -0
  120. package/dist/setup/distribution.js.map +1 -0
  121. package/dist/setup/env-file.d.ts +23 -0
  122. package/dist/setup/env-file.d.ts.map +1 -0
  123. package/dist/setup/env-file.js +141 -0
  124. package/dist/setup/env-file.js.map +1 -0
  125. package/dist/setup/format.d.ts +4 -0
  126. package/dist/setup/format.d.ts.map +1 -0
  127. package/dist/setup/format.js +58 -0
  128. package/dist/setup/format.js.map +1 -0
  129. package/dist/setup/index.d.ts +17 -0
  130. package/dist/setup/index.d.ts.map +1 -0
  131. package/dist/setup/index.js +45 -0
  132. package/dist/setup/index.js.map +1 -0
  133. package/dist/setup/install-path.d.ts +3 -0
  134. package/dist/setup/install-path.d.ts.map +1 -0
  135. package/dist/setup/install-path.js +26 -0
  136. package/dist/setup/install-path.js.map +1 -0
  137. package/dist/setup/installation-state.d.ts +29 -0
  138. package/dist/setup/installation-state.d.ts.map +1 -0
  139. package/dist/setup/installation-state.js +83 -0
  140. package/dist/setup/installation-state.js.map +1 -0
  141. package/dist/setup/installation-status.d.ts +14 -0
  142. package/dist/setup/installation-status.d.ts.map +1 -0
  143. package/dist/setup/installation-status.js +36 -0
  144. package/dist/setup/installation-status.js.map +1 -0
  145. package/dist/setup/materialize-install.d.ts +24 -0
  146. package/dist/setup/materialize-install.d.ts.map +1 -0
  147. package/dist/setup/materialize-install.js +108 -0
  148. package/dist/setup/materialize-install.js.map +1 -0
  149. package/dist/setup/probe-spawn.d.ts +16 -0
  150. package/dist/setup/probe-spawn.d.ts.map +1 -0
  151. package/dist/setup/probe-spawn.js +87 -0
  152. package/dist/setup/probe-spawn.js.map +1 -0
  153. package/dist/setup/read-options.d.ts +15 -0
  154. package/dist/setup/read-options.d.ts.map +1 -0
  155. package/dist/setup/read-options.js +69 -0
  156. package/dist/setup/read-options.js.map +1 -0
  157. package/dist/setup/run-onboarding.d.ts +22 -0
  158. package/dist/setup/run-onboarding.d.ts.map +1 -0
  159. package/dist/setup/run-onboarding.js +273 -0
  160. package/dist/setup/run-onboarding.js.map +1 -0
  161. package/dist/setup/run-provision.d.ts +17 -0
  162. package/dist/setup/run-provision.d.ts.map +1 -0
  163. package/dist/setup/run-provision.js +224 -0
  164. package/dist/setup/run-provision.js.map +1 -0
  165. package/dist/setup/run-setup.d.ts +26 -0
  166. package/dist/setup/run-setup.d.ts.map +1 -0
  167. package/dist/setup/run-setup.js +227 -0
  168. package/dist/setup/run-setup.js.map +1 -0
  169. package/dist/setup/secrets.d.ts +2 -0
  170. package/dist/setup/secrets.d.ts.map +1 -0
  171. package/dist/setup/secrets.js +8 -0
  172. package/dist/setup/secrets.js.map +1 -0
  173. package/dist/setup/setup-report.d.ts +19 -0
  174. package/dist/setup/setup-report.d.ts.map +1 -0
  175. package/dist/setup/setup-report.js +35 -0
  176. package/dist/setup/setup-report.js.map +1 -0
  177. package/dist/tsconfig.tsbuildinfo +1 -1
  178. package/package.json +3 -3
  179. package/templates/compose-install/compose.yml +307 -0
  180. package/templates/compose-install/distribution.json +5 -0
  181. package/templates/compose-install/upgrade-catalog.json +39 -0
@@ -0,0 +1,108 @@
1
+ import { mkdir, readFile, stat } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { CLI_VERSION } from "../version.js";
4
+ import { writeFileAtomic } from "./atomic-write.js";
5
+ import { buildInstallEnvValues, detectShellEnvConflicts, readInstallEnvFile, renderInstallEnvFile, } from "./env-file.js";
6
+ import { assessInstallDirectory, INSTALLATION_MARKER_RELATIVE, renderInstallationMarker, } from "./installation-state.js";
7
+ import { resolveSetupImageRef } from "./acceptance-install.js";
8
+ import { deriveComposeProjectName } from "./compose-project.js";
9
+ import { generateSecretHex } from "./secrets.js";
10
+ export async function materializeInstallation(input) {
11
+ const installDir = input.options.installDir;
12
+ const assessment = await assessInstallDirectory(installDir);
13
+ if (assessment.kind === "foreign") {
14
+ throw new MaterializeInstallError("foreign_directory", `Installation directory contains unrelated files: ${assessment.foreignEntries.join(", ")}`);
15
+ }
16
+ if (assessment.foreignEntries.length > 0) {
17
+ throw new MaterializeInstallError("foreign_directory", `Installation directory contains unrelated files: ${assessment.foreignEntries.join(", ")}`);
18
+ }
19
+ await mkdir(installDir, { recursive: true });
20
+ await mkdir(path.join(installDir, ".osva"), { recursive: true });
21
+ const envPath = path.join(installDir, ".env");
22
+ const composePath = path.join(installDir, "compose.yml");
23
+ const markerPath = path.join(installDir, INSTALLATION_MARKER_RELATIVE);
24
+ const existingEnv = await readInstallEnvFile(envPath);
25
+ const preservedSecrets = existingEnv !== undefined;
26
+ const composeProjectName = deriveComposeProjectName(installDir);
27
+ const envValues = buildInstallEnvValues({
28
+ imageRef: resolveSetupImageRef({
29
+ distributionImageRef: input.distribution.manifest.imageRef,
30
+ processEnv: input.processEnv,
31
+ }),
32
+ composeProjectName,
33
+ webPort: input.options.webPort,
34
+ mcpPort: input.options.mcpPort,
35
+ consolePort: input.options.consolePort,
36
+ existing: existingEnv,
37
+ generateSecret: () => generateSecretHex(32),
38
+ });
39
+ const conflicts = detectShellEnvConflicts(envValues, input.processEnv);
40
+ if (conflicts.length > 0) {
41
+ const keys = conflicts.map((conflict) => conflict.key).join(", ");
42
+ throw new MaterializeInstallError("env_conflict", `Host environment variables override installation secrets and differ from ${path.basename(envPath)}: ${keys}. Unset them or align values before retrying.`);
43
+ }
44
+ const wroteCompose = await writeComposeIfNeeded(composePath, input.distribution.composeYaml, assessment, input.options.authorizeExisting);
45
+ const wroteEnv = await writeEnvIfNeeded(envPath, envValues, existingEnv);
46
+ const marker = renderInstallationMarker({
47
+ platformVersion: input.distribution.manifest.platformVersion,
48
+ imageRef: envValues.OSVA_IMAGE,
49
+ cliVersion: CLI_VERSION,
50
+ installDir,
51
+ composeProjectName: envValues.COMPOSE_PROJECT_NAME,
52
+ existing: assessment.marker,
53
+ });
54
+ await writeFileAtomic(markerPath, `${JSON.stringify(marker, null, 2)}\n`, {
55
+ restrictPermissions: true,
56
+ });
57
+ return {
58
+ assessment,
59
+ envValues,
60
+ envPath,
61
+ composePath,
62
+ markerPath,
63
+ preservedSecrets,
64
+ wroteCompose,
65
+ wroteEnv,
66
+ };
67
+ }
68
+ async function writeComposeIfNeeded(composePath, composeYaml, assessment, authorizeExisting) {
69
+ const exists = await pathExists(composePath);
70
+ if (exists && assessment.kind === "osva_installation" && !authorizeExisting) {
71
+ return false;
72
+ }
73
+ await writeFileAtomic(composePath, composeYaml);
74
+ return true;
75
+ }
76
+ async function writeEnvIfNeeded(envPath, values, existing) {
77
+ const rendered = renderInstallEnvFile(values);
78
+ if (existing !== undefined) {
79
+ try {
80
+ const current = await readFile(envPath, "utf8");
81
+ if (current === rendered) {
82
+ return false;
83
+ }
84
+ }
85
+ catch {
86
+ // write below
87
+ }
88
+ }
89
+ await writeFileAtomic(envPath, rendered, { restrictPermissions: true });
90
+ return true;
91
+ }
92
+ async function pathExists(targetPath) {
93
+ try {
94
+ await stat(targetPath);
95
+ return true;
96
+ }
97
+ catch {
98
+ return false;
99
+ }
100
+ }
101
+ export class MaterializeInstallError extends Error {
102
+ code;
103
+ constructor(code, message) {
104
+ super(message);
105
+ this.code = code;
106
+ }
107
+ }
108
+ //# sourceMappingURL=materialize-install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"materialize-install.js","sourceRoot":"","sources":["../../src/setup/materialize-install.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,kBAAkB,EAClB,oBAAoB,GAErB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,sBAAsB,EACtB,4BAA4B,EAC5B,wBAAwB,GAEzB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAcjD,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,KAI7C;IACC,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;IAC5C,MAAM,UAAU,GAAG,MAAM,sBAAsB,CAAC,UAAU,CAAC,CAAC;IAC5D,IAAI,UAAU,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAClC,MAAM,IAAI,uBAAuB,CAC/B,mBAAmB,EACnB,oDAAoD,UAAU,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC3F,CAAC;IACJ,CAAC;IACD,IAAI,UAAU,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzC,MAAM,IAAI,uBAAuB,CAC/B,mBAAmB,EACnB,oDAAoD,UAAU,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC3F,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEjE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAC9C,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;IACzD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,4BAA4B,CAAC,CAAC;IAEvE,MAAM,WAAW,GAAG,MAAM,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACtD,MAAM,gBAAgB,GAAG,WAAW,KAAK,SAAS,CAAC;IACnD,MAAM,kBAAkB,GAAG,wBAAwB,CAAC,UAAU,CAAC,CAAC;IAChE,MAAM,SAAS,GAAG,qBAAqB,CAAC;QACtC,QAAQ,EAAE,oBAAoB,CAAC;YAC7B,oBAAoB,EAAE,KAAK,CAAC,YAAY,CAAC,QAAQ,CAAC,QAAQ;YAC1D,UAAU,EAAE,KAAK,CAAC,UAAU;SAC7B,CAAC;QACF,kBAAkB;QAClB,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,OAAO;QAC9B,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,OAAO;QAC9B,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC,WAAW;QACtC,QAAQ,EAAE,WAAW;QACrB,cAAc,EAAE,GAAG,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;KAC5C,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,uBAAuB,CAAC,SAAS,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IACvE,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClE,MAAM,IAAI,uBAAuB,CAC/B,cAAc,EACd,4EAA4E,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,IAAI,+CAA+C,CAC3J,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,oBAAoB,CAC7C,WAAW,EACX,KAAK,CAAC,YAAY,CAAC,WAAW,EAC9B,UAAU,EACV,KAAK,CAAC,OAAO,CAAC,iBAAiB,CAChC,CAAC;IACF,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,OAAO,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;IACzE,MAAM,MAAM,GAAG,wBAAwB,CAAC;QACtC,eAAe,EAAE,KAAK,CAAC,YAAY,CAAC,QAAQ,CAAC,eAAe;QAC5D,QAAQ,EAAE,SAAS,CAAC,UAAU;QAC9B,UAAU,EAAE,WAAW;QACvB,UAAU;QACV,kBAAkB,EAAE,SAAS,CAAC,oBAAoB;QAClD,QAAQ,EAAE,UAAU,CAAC,MAAM;KAC5B,CAAC,CAAC;IACH,MAAM,eAAe,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;QACxE,mBAAmB,EAAE,IAAI;KAC1B,CAAC,CAAC;IAEH,OAAO;QACL,UAAU;QACV,SAAS;QACT,OAAO;QACP,WAAW;QACX,UAAU;QACV,gBAAgB;QAChB,YAAY;QACZ,QAAQ;KACT,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,oBAAoB,CACjC,WAAmB,EACnB,WAAmB,EACnB,UAAsC,EACtC,iBAA0B;IAE1B,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,WAAW,CAAC,CAAC;IAC7C,IAAI,MAAM,IAAI,UAAU,CAAC,IAAI,KAAK,mBAAmB,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC5E,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,eAAe,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IAChD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,OAAe,EACf,MAAwB,EACxB,QAAyC;IAEzC,MAAM,QAAQ,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC9C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAChD,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;gBACzB,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,cAAc;QAChB,CAAC;IACH,CAAC;IACD,MAAM,eAAe,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,mBAAmB,EAAE,IAAI,EAAE,CAAC,CAAC;IACxE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,UAAkB;IAC1C,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,UAAU,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IACvC,IAAI,CAAuC;IAEpD,YAAY,IAA0C,EAAE,OAAe;QACrE,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF"}
@@ -0,0 +1,16 @@
1
+ export interface ProbeSpawnResult {
2
+ readonly status: number | null;
3
+ readonly stdout: string;
4
+ readonly stderr: string;
5
+ readonly error: NodeJS.ErrnoException | undefined;
6
+ }
7
+ export type ProbeSpawnFn = (executable: string, args: readonly string[], timeoutMs: number, processEnv?: NodeJS.ProcessEnv) => ProbeSpawnResult;
8
+ /** Cap Docker probe output buffering (spawnSync default is 1 MiB). */
9
+ export declare const PROBE_SPAWN_MAX_BUFFER_BYTES: number;
10
+ export declare function defaultProbeSpawn(executable: string, args: readonly string[], timeoutMs: number, processEnv?: NodeJS.ProcessEnv): ProbeSpawnResult;
11
+ /** Stream subprocess stdout/stderr with bounded chunk-safe secret redaction. */
12
+ export declare function spawnStreamingCommand(executable: string, args: readonly string[], processEnv?: NodeJS.ProcessEnv): Promise<{
13
+ readonly exitCode: number | null;
14
+ readonly signal: NodeJS.Signals | null;
15
+ }>;
16
+ //# sourceMappingURL=probe-spawn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe-spawn.d.ts","sourceRoot":"","sources":["../../src/setup/probe-spawn.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,cAAc,GAAG,SAAS,CAAC;CACnD;AAED,MAAM,MAAM,YAAY,GAAG,CACzB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,MAAM,CAAC,UAAU,KAC3B,gBAAgB,CAAC;AAEtB,sEAAsE;AACtE,eAAO,MAAM,4BAA4B,QAAa,CAAC;AAEvD,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,SAAS,EAAE,MAAM,EACjB,UAAU,GAAE,MAAM,CAAC,UAAwB,GAC1C,gBAAgB,CA0BlB;AAED,gFAAgF;AAChF,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,UAAU,GAAE,MAAM,CAAC,UAAwB,GAC1C,OAAO,CAAC;IACT,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;CACxC,CAAC,CAyDD"}
@@ -0,0 +1,87 @@
1
+ import { spawn, spawnSync, } from "node:child_process";
2
+ import { createStreamingSecretRedactor } from "../doctor/streaming-redact.js";
3
+ /** Cap Docker probe output buffering (spawnSync default is 1 MiB). */
4
+ export const PROBE_SPAWN_MAX_BUFFER_BYTES = 256 * 1024;
5
+ export function defaultProbeSpawn(executable, args, timeoutMs, processEnv = process.env) {
6
+ let result;
7
+ try {
8
+ result = spawnSync(executable, [...args], {
9
+ encoding: "utf8",
10
+ stdio: "pipe",
11
+ shell: false,
12
+ timeout: timeoutMs,
13
+ maxBuffer: PROBE_SPAWN_MAX_BUFFER_BYTES,
14
+ env: processEnv,
15
+ });
16
+ }
17
+ catch (error) {
18
+ const errno = error;
19
+ return {
20
+ status: null,
21
+ stdout: "",
22
+ stderr: errno.message ?? String(error),
23
+ error: errno,
24
+ };
25
+ }
26
+ return {
27
+ status: result.status,
28
+ stdout: result.stdout ?? "",
29
+ stderr: result.stderr ?? "",
30
+ error: result.error,
31
+ };
32
+ }
33
+ /** Stream subprocess stdout/stderr with bounded chunk-safe secret redaction. */
34
+ export function spawnStreamingCommand(executable, args, processEnv = process.env) {
35
+ return new Promise((resolve, reject) => {
36
+ let child;
37
+ try {
38
+ child = spawn(executable, [...args], {
39
+ stdio: ["ignore", "pipe", "pipe"],
40
+ shell: false,
41
+ env: processEnv,
42
+ });
43
+ }
44
+ catch (error) {
45
+ reject(error);
46
+ return;
47
+ }
48
+ const stdoutRedactor = createStreamingSecretRedactor((text) => {
49
+ process.stdout.write(text);
50
+ });
51
+ const stderrRedactor = createStreamingSecretRedactor((text) => {
52
+ process.stderr.write(text);
53
+ });
54
+ child.stdout?.on("data", (chunk) => {
55
+ stdoutRedactor.write(typeof chunk === "string" ? chunk : chunk.toString("utf8"));
56
+ });
57
+ child.stderr?.on("data", (chunk) => {
58
+ stderrRedactor.write(typeof chunk === "string" ? chunk : chunk.toString("utf8"));
59
+ });
60
+ const onInterrupt = () => {
61
+ if (child.killed) {
62
+ return;
63
+ }
64
+ if (process.platform === "win32") {
65
+ child.kill();
66
+ }
67
+ else {
68
+ child.kill("SIGTERM");
69
+ }
70
+ };
71
+ process.on("SIGINT", onInterrupt);
72
+ process.on("SIGTERM", onInterrupt);
73
+ child.on("error", (error) => {
74
+ process.off("SIGINT", onInterrupt);
75
+ process.off("SIGTERM", onInterrupt);
76
+ reject(error);
77
+ });
78
+ child.on("close", (exitCode, signal) => {
79
+ stdoutRedactor.flush();
80
+ stderrRedactor.flush();
81
+ process.off("SIGINT", onInterrupt);
82
+ process.off("SIGTERM", onInterrupt);
83
+ resolve({ exitCode, signal });
84
+ });
85
+ });
86
+ }
87
+ //# sourceMappingURL=probe-spawn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe-spawn.js","sourceRoot":"","sources":["../../src/setup/probe-spawn.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export interface SetupOptions {
2
+ readonly webPort: number;
3
+ readonly mcpPort: number;
4
+ readonly consolePort: number;
5
+ readonly installDir: string;
6
+ readonly preflightOnly: boolean;
7
+ readonly authorizeExisting: boolean;
8
+ readonly adminEmail: string;
9
+ readonly adminName: string;
10
+ readonly organizationName: string;
11
+ readonly workspaceName: string;
12
+ }
13
+ export declare function readSetupOptions(flags: Readonly<Record<string, string | boolean>>, env?: NodeJS.ProcessEnv, platform?: NodeJS.Platform): SetupOptions;
14
+ export declare function parsePortNumber(raw: string, flagName: string): number;
15
+ //# sourceMappingURL=read-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-options.d.ts","sourceRoot":"","sources":["../../src/setup/read-options.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,EACjD,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,YAAY,CAgEd;AAkCD,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAarE"}
@@ -0,0 +1,69 @@
1
+ import { resolveInstallDir } from "./install-path.js";
2
+ export function readSetupOptions(flags, env = process.env, platform = process.platform) {
3
+ const webPort = parsePortFlag(flags["web-port"], env.OSVA_PUBLISH_WEB_PORT, 8080, "web-port");
4
+ const mcpPort = parsePortFlag(flags["mcp-port"], env.OSVA_PUBLISH_MCP_PORT, 3100, "mcp-port");
5
+ const consolePort = parsePortFlag(flags["console-port"], env.OSVA_PUBLISH_CONSOLE_PORT, 4174, "console-port");
6
+ const publishPorts = [
7
+ { port: webPort, label: "web" },
8
+ { port: mcpPort, label: "mcp" },
9
+ { port: consolePort, label: "console" },
10
+ ];
11
+ for (let left = 0; left < publishPorts.length; left += 1) {
12
+ for (let right = left + 1; right < publishPorts.length; right += 1) {
13
+ const a = publishPorts[left];
14
+ const b = publishPorts[right];
15
+ if (a !== undefined && b !== undefined && a.port === b.port) {
16
+ throw new Error(`Publish ports must be distinct (${a.label} and ${b.label} both use ${String(a.port)}).`);
17
+ }
18
+ }
19
+ }
20
+ const adminEmail = readOptionalStringFlag(flags["admin-email"], env.OSVA_SETUP_ADMIN_EMAIL);
21
+ const adminName = readOptionalStringFlag(flags["admin-name"], env.OSVA_SETUP_ADMIN_NAME) ??
22
+ "Initial Owner";
23
+ const organizationName = readOptionalStringFlag(flags["organization-name"], env.OSVA_SETUP_ORGANIZATION_NAME) ?? "Default Organization";
24
+ const workspaceName = readOptionalStringFlag(flags["workspace-name"], env.OSVA_BOOTSTRAP_WORKSPACE_NAME) ?? "Default Workspace";
25
+ return {
26
+ webPort,
27
+ mcpPort,
28
+ consolePort,
29
+ installDir: resolveInstallDir(flags, env, platform),
30
+ preflightOnly: flags["preflight-only"] === true,
31
+ authorizeExisting: flags.yes === true,
32
+ adminEmail: adminEmail ?? "",
33
+ adminName,
34
+ organizationName,
35
+ workspaceName,
36
+ };
37
+ }
38
+ function readOptionalStringFlag(flagValue, envValue) {
39
+ if (typeof flagValue === "string" && flagValue.trim().length > 0) {
40
+ return flagValue.trim();
41
+ }
42
+ const trimmedEnv = envValue?.trim();
43
+ return trimmedEnv === undefined || trimmedEnv.length === 0
44
+ ? undefined
45
+ : trimmedEnv;
46
+ }
47
+ function parsePortFlag(flagValue, envValue, fallback, flagName) {
48
+ if (typeof flagValue === "boolean") {
49
+ throw new Error(`--${flagName} requires a port number.`);
50
+ }
51
+ const raw = typeof flagValue === "string" && flagValue.trim().length > 0
52
+ ? flagValue.trim()
53
+ : envValue?.trim();
54
+ if (raw === undefined || raw.length === 0) {
55
+ return fallback;
56
+ }
57
+ return parsePortNumber(raw, flagName);
58
+ }
59
+ export function parsePortNumber(raw, flagName) {
60
+ if (!/^\d+$/.test(raw)) {
61
+ throw new Error(`Invalid --${flagName} or OSVA_PUBLISH_* value '${raw}'; use an integer from 1 to 65535.`);
62
+ }
63
+ const port = Number(raw);
64
+ if (!Number.isInteger(port) || port < 1 || port > 65_535) {
65
+ throw new Error(`Invalid --${flagName} or OSVA_PUBLISH_* value '${raw}'; use an integer from 1 to 65535.`);
66
+ }
67
+ return port;
68
+ }
69
+ //# sourceMappingURL=read-options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-options.js","sourceRoot":"","sources":["../../src/setup/read-options.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { DoctorCheck } from "../doctor/types.js";
2
+ import { type ComposeExecContext } from "./compose-exec.js";
3
+ import { type AdministratorBootstrapPhase } from "./installation-status.js";
4
+ import type { ProbeSpawnFn } from "./probe-spawn.js";
5
+ import type { SetupOptions } from "./read-options.js";
6
+ export declare const COMPOSE_ONBOARDING_TIMEOUT_MS = 300000;
7
+ export interface OnboardingResult {
8
+ readonly checks: readonly DoctorCheck[];
9
+ readonly consoleUrl: string;
10
+ /** One-time password setup token for interactive display only (never persisted). */
11
+ readonly setupTokenForOperator?: string;
12
+ readonly administratorPhase: AdministratorBootstrapPhase | undefined;
13
+ }
14
+ export declare function runSetupOnboarding(input: {
15
+ readonly options: SetupOptions;
16
+ readonly execCtx: ComposeExecContext;
17
+ readonly spawn: ProbeSpawnFn | undefined;
18
+ readonly fetch: typeof fetch;
19
+ readonly mutateInstallation: boolean;
20
+ readonly processEnv?: NodeJS.ProcessEnv;
21
+ }): Promise<OnboardingResult>;
22
+ //# sourceMappingURL=run-onboarding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-onboarding.d.ts","sourceRoot":"","sources":["../../src/setup/run-onboarding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAOtD,OAAO,EAKL,KAAK,kBAAkB,EACxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAGL,KAAK,2BAA2B,EAEjC,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAKrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,eAAO,MAAM,6BAA6B,SAAU,CAAC;AAErD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC;IACxC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,oFAAoF;IACpF,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IACxC,QAAQ,CAAC,kBAAkB,EAAE,2BAA2B,GAAG,SAAS,CAAC;CACtE;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE;IAC9C,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,OAAO,KAAK,CAAC;IAC7B,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzC,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAgQ5B"}
@@ -0,0 +1,273 @@
1
+ import { redactSecrets } from "../doctor/redact.js";
2
+ import { parseIdentityBootstrapSetupToken, parseWorkspaceBootstrapOutput, redactBootstrapSubprocessOutput, } from "./bootstrap-capture.js";
3
+ import { assertComposeSuccess, buildComposeSpawnEnv, ComposeExecError, runComposeCommand, } from "./compose-exec.js";
4
+ import { classifyAdministratorBootstrapPhase, parseInstallationStatusJson, } from "./installation-status.js";
5
+ import { writeAcceptanceBootstrapKeyFile, writeAcceptanceSetupTokenFile, } from "./acceptance-install.js";
6
+ export const COMPOSE_ONBOARDING_TIMEOUT_MS = 300_000;
7
+ export async function runSetupOnboarding(input) {
8
+ const processEnv = input.processEnv ?? process.env;
9
+ const checks = [];
10
+ const consoleUrl = `http://127.0.0.1:${String(input.options.consolePort)}`;
11
+ let setupTokenForOperator;
12
+ let administratorPhase;
13
+ if (!(await probeConsoleDistribution(input.execCtx, input.spawn))) {
14
+ checks.push(failCheck("console_distribution", "The pinned OSVA image does not include Console assets (apps/console).", "Re-run `osva setup --yes` after upgrading OSVA_IMAGE to a release that packages Console, or install a matching CLI bundle."));
15
+ checks.push(skipCheck("console_ready", "Skipped Console readiness because Console is unavailable in the OSVA image."));
16
+ checks.push(skipCheck("administrator_bootstrapped", "Skipped administrator bootstrap because Console distribution is unavailable."));
17
+ return { checks, consoleUrl, setupTokenForOperator, administratorPhase };
18
+ }
19
+ checks.push(passCheck("console_distribution", "Console server assets are present in the pinned OSVA image."));
20
+ if (input.mutateInstallation) {
21
+ startConsoleService(input.execCtx, input.spawn);
22
+ }
23
+ try {
24
+ await waitForConsoleReady(input.fetch, consoleUrl);
25
+ checks.push(passCheck("console_ready", `Console is ready at ${consoleUrl}.`));
26
+ }
27
+ catch (error) {
28
+ checks.push(failCheck("console_ready", redactSecrets(error instanceof Error
29
+ ? error.message
30
+ : "Console did not become ready."), "Inspect `docker compose --project-directory <install-dir> logs console` and retry `osva setup`."));
31
+ return { checks, consoleUrl, setupTokenForOperator, administratorPhase };
32
+ }
33
+ let status;
34
+ try {
35
+ status = await readInstallationStatus(input.execCtx, input.spawn);
36
+ }
37
+ catch (error) {
38
+ checks.push(failCheck("administrator_bootstrapped", redactSecrets(error instanceof Error
39
+ ? error.message
40
+ : "Could not read installation status."), "Ensure PostgreSQL is healthy, then retry `osva setup`."));
41
+ return { checks, consoleUrl, setupTokenForOperator, administratorPhase };
42
+ }
43
+ administratorPhase = classifyAdministratorBootstrapPhase(status);
44
+ if (!input.mutateInstallation) {
45
+ checks.push(...reportReadOnlyAdministratorState(administratorPhase, consoleUrl));
46
+ return { checks, consoleUrl, setupTokenForOperator, administratorPhase };
47
+ }
48
+ if (administratorPhase === "administrator_ready") {
49
+ checks.push(passCheck("administrator_bootstrapped", "A human administrator is already linked to this installation."));
50
+ checks.push(passCheck("administrator_setup_complete", "Initial administrator password setup appears complete."));
51
+ checks.push(passCheck("installation_complete", `Installation complete. Open ${consoleUrl}, sign in, and continue Console onboarding.`));
52
+ checks.push(skipCheck("first_agent_run_succeeded", "First agent execution is not verified by the installer; complete Agent Studio onboarding in the Console."));
53
+ return { checks, consoleUrl, setupTokenForOperator, administratorPhase };
54
+ }
55
+ if (administratorPhase === "administrator_pending_password_setup") {
56
+ checks.push(passCheck("administrator_bootstrapped", "Human administrator exists but password setup is still pending."));
57
+ checks.push(skipCheck("administrator_setup_complete", `Complete password setup at ${consoleUrl}/setup before signing in.`));
58
+ checks.push(skipCheck("installation_complete", "Installation is not complete until administrator password setup and sign-in succeed."));
59
+ return { checks, consoleUrl, setupTokenForOperator, administratorPhase };
60
+ }
61
+ if (administratorPhase === "multiple_unlinked_workspaces") {
62
+ checks.push(warnCheck("administrator_bootstrapped", "Multiple workspaces exist without linked human administrators.", "Run identity bootstrap manually with explicit --workspace-id values for each workspace, or consolidate workspaces before retrying `osva setup`."));
63
+ checks.push(skipCheck("installation_complete", "Installation is not complete until each workspace has a linked human administrator."));
64
+ return { checks, consoleUrl, setupTokenForOperator, administratorPhase };
65
+ }
66
+ if (status.apiKeyCount === 0) {
67
+ try {
68
+ await runWorkspaceBootstrapJob(input.execCtx, input.spawn, input.options, processEnv);
69
+ status = await readInstallationStatus(input.execCtx, input.spawn);
70
+ administratorPhase = classifyAdministratorBootstrapPhase(status);
71
+ }
72
+ catch (error) {
73
+ checks.push(failCheck("administrator_bootstrapped", redactSecrets(error instanceof Error
74
+ ? error.message
75
+ : "Workspace bootstrap failed."), "Inspect bootstrap job logs and retry `osva setup`."));
76
+ return { checks, consoleUrl, setupTokenForOperator, administratorPhase };
77
+ }
78
+ }
79
+ if (administratorPhase === "fresh_installation" ||
80
+ administratorPhase === "workspace_without_human_administrator" ||
81
+ administratorPhase === "ambiguous_workspace_state") {
82
+ if (input.options.adminEmail.trim().length === 0) {
83
+ checks.push(failCheck("administrator_bootstrapped", "Administrator email is required for initial human identity bootstrap.", "Re-run with --admin-email owner@example.com (and optional --admin-name / --organization-name)."));
84
+ checks.push(skipCheck("installation_complete", "Installation is not complete until administrator bootstrap succeeds."));
85
+ return { checks, consoleUrl, setupTokenForOperator, administratorPhase };
86
+ }
87
+ try {
88
+ const token = await runIdentityBootstrapJob(input.execCtx, input.spawn, input.options, status);
89
+ setupTokenForOperator = token;
90
+ if (token !== undefined) {
91
+ await writeAcceptanceSetupTokenFile({ processEnv, token });
92
+ }
93
+ checks.push(passCheck("administrator_bootstrapped", `Initial human administrator ${input.options.adminEmail} was linked to the workspace.`));
94
+ if (token !== undefined) {
95
+ checks.push(skipCheck("administrator_setup_complete", `Open ${consoleUrl}/setup and enter the one-time setup token printed below (not stored in installation files or JSON output).`));
96
+ }
97
+ checks.push(skipCheck("installation_complete", "Installation is not complete until password setup and sign-in succeed in the Console."));
98
+ checks.push(skipCheck("first_agent_run_succeeded", "First agent execution is not verified by the installer."));
99
+ }
100
+ catch (error) {
101
+ checks.push(failCheck("administrator_bootstrapped", redactSecrets(error instanceof Error
102
+ ? error.message
103
+ : "Human identity bootstrap failed."), "Resolve the reported issue and retry `osva setup` (existing organizations are not reset)."));
104
+ }
105
+ }
106
+ return { checks, consoleUrl, setupTokenForOperator, administratorPhase };
107
+ }
108
+ function reportReadOnlyAdministratorState(phase, consoleUrl) {
109
+ if (phase === "administrator_ready") {
110
+ return [
111
+ passCheck("administrator_bootstrapped", "Human administrator is configured."),
112
+ passCheck("administrator_setup_complete", "Initial administrator password setup appears complete."),
113
+ skipCheck("installation_complete", `Platform is operational. Open ${consoleUrl} to sign in (re-run with --yes to reconcile services).`),
114
+ ];
115
+ }
116
+ if (phase === "administrator_pending_password_setup") {
117
+ return [
118
+ passCheck("administrator_bootstrapped", "Human administrator exists; password setup is pending."),
119
+ skipCheck("administrator_setup_complete", `Complete setup at ${consoleUrl}/setup (re-run with --yes to reconcile services).`),
120
+ ];
121
+ }
122
+ return [
123
+ skipCheck("administrator_bootstrapped", "Human administrator bootstrap is incomplete. Re-run `osva setup --yes` with --admin-email to continue."),
124
+ ];
125
+ }
126
+ async function probeConsoleDistribution(ctx, spawn) {
127
+ const script = "try{require('fs').accessSync('/app/apps/console/dist/server/main.js');process.exit(0)}catch{process.exit(2)}";
128
+ const result = runComposeCommand(ctx, [
129
+ "run",
130
+ "--rm",
131
+ "--no-deps",
132
+ "-T",
133
+ "--entrypoint",
134
+ "node",
135
+ "web",
136
+ "-e",
137
+ script,
138
+ ], {
139
+ spawn,
140
+ timeoutMs: COMPOSE_ONBOARDING_TIMEOUT_MS,
141
+ processEnv: buildComposeSpawnEnv(ctx),
142
+ });
143
+ return result.status === 0;
144
+ }
145
+ function startConsoleService(ctx, spawn) {
146
+ const result = runComposeCommand(ctx, ["up", "-d", "--no-build", "--wait", "console"], {
147
+ spawn,
148
+ timeoutMs: COMPOSE_ONBOARDING_TIMEOUT_MS,
149
+ processEnv: buildComposeSpawnEnv(ctx),
150
+ });
151
+ assertComposeSuccess(result, "Starting Console");
152
+ }
153
+ async function waitForConsoleReady(fetchImpl, consoleUrl) {
154
+ let lastStatus;
155
+ for (let attempt = 0; attempt < 45; attempt += 1) {
156
+ try {
157
+ const response = await fetchImpl(`${consoleUrl}/`);
158
+ lastStatus = response.status;
159
+ if (response.ok) {
160
+ return;
161
+ }
162
+ }
163
+ catch {
164
+ // retry
165
+ }
166
+ await delay(2_000);
167
+ }
168
+ throw new ComposeExecError("command_failed", `Timed out waiting for Console at ${consoleUrl}${lastStatus === undefined ? "" : ` (last status ${String(lastStatus)})`}.`);
169
+ }
170
+ async function readInstallationStatus(ctx, spawn) {
171
+ const result = runComposeCommand(ctx, ["--profile", "bootstrap", "run", "--rm", "-T", "installation-status"], {
172
+ spawn,
173
+ timeoutMs: COMPOSE_ONBOARDING_TIMEOUT_MS,
174
+ processEnv: buildComposeSpawnEnv(ctx),
175
+ });
176
+ assertComposeSuccess(result, "Installation status probe");
177
+ return parseInstallationStatusJson(result.stdout);
178
+ }
179
+ async function runWorkspaceBootstrapJob(ctx, spawn, options, processEnv) {
180
+ const args = [
181
+ "--profile",
182
+ "bootstrap",
183
+ "run",
184
+ "--rm",
185
+ "-T",
186
+ "-e",
187
+ `OSVA_BOOTSTRAP_WORKSPACE_NAME=${options.workspaceName}`,
188
+ "bootstrap",
189
+ ];
190
+ const result = runComposeCommand(ctx, args, {
191
+ spawn,
192
+ timeoutMs: COMPOSE_ONBOARDING_TIMEOUT_MS,
193
+ processEnv: buildComposeSpawnEnv(ctx),
194
+ });
195
+ if (result.status !== 0) {
196
+ const detail = redactBootstrapSubprocessOutput(result.stderr || result.stdout);
197
+ throw new ComposeExecError("command_failed", detail.length > 0 ? detail : "Workspace bootstrap failed.");
198
+ }
199
+ const parsed = parseWorkspaceBootstrapOutput(result.stdout);
200
+ if (!parsed.alreadyCompleted && parsed.workspaceId === undefined) {
201
+ throw new ComposeExecError("command_failed", "Workspace bootstrap completed without a workspace id.");
202
+ }
203
+ if (parsed.apiKey !== undefined) {
204
+ await writeAcceptanceBootstrapKeyFile({
205
+ processEnv,
206
+ apiKey: parsed.apiKey,
207
+ });
208
+ }
209
+ }
210
+ async function runIdentityBootstrapJob(ctx, spawn, options, status) {
211
+ const identityArgs = [
212
+ "--profile",
213
+ "bootstrap",
214
+ "run",
215
+ "--rm",
216
+ "-T",
217
+ "identity-bootstrap",
218
+ "--",
219
+ "--email",
220
+ options.adminEmail,
221
+ "--name",
222
+ options.adminName,
223
+ "--organization-name",
224
+ options.organizationName,
225
+ ];
226
+ if (status.unlinkedWorkspaceIds.length === 1) {
227
+ identityArgs.push("--workspace-id", status.unlinkedWorkspaceIds[0]);
228
+ }
229
+ else if (status.unlinkedWorkspaceIds.length > 1) {
230
+ identityArgs.push("--all-unlinked-workspaces");
231
+ }
232
+ else if (status.workspaceCount === 1) {
233
+ const workspaceBootstrap = await readLatestWorkspaceId(ctx, spawn);
234
+ if (workspaceBootstrap !== undefined) {
235
+ identityArgs.push("--workspace-id", workspaceBootstrap);
236
+ }
237
+ }
238
+ const result = runComposeCommand(ctx, identityArgs, {
239
+ spawn,
240
+ timeoutMs: COMPOSE_ONBOARDING_TIMEOUT_MS,
241
+ processEnv: buildComposeSpawnEnv(ctx),
242
+ });
243
+ if (result.status !== 0) {
244
+ const detail = redactBootstrapSubprocessOutput(result.stderr || result.stdout);
245
+ throw new ComposeExecError("command_failed", detail.length > 0 ? detail : "Human identity bootstrap failed.");
246
+ }
247
+ return parseIdentityBootstrapSetupToken(result.stdout);
248
+ }
249
+ async function readLatestWorkspaceId(ctx, spawn) {
250
+ const status = await readInstallationStatus(ctx, spawn);
251
+ if (status.unlinkedWorkspaceIds.length === 1) {
252
+ return status.unlinkedWorkspaceIds[0];
253
+ }
254
+ return status.unlinkedWorkspaceIds[0];
255
+ }
256
+ function delay(ms) {
257
+ return new Promise((resolve) => {
258
+ setTimeout(resolve, ms);
259
+ });
260
+ }
261
+ function passCheck(id, message) {
262
+ return { id, status: "PASS", message };
263
+ }
264
+ function warnCheck(id, message, remediation) {
265
+ return { id, status: "WARN", message, remediation };
266
+ }
267
+ function failCheck(id, message, remediation) {
268
+ return { id, status: "FAIL", message, remediation };
269
+ }
270
+ function skipCheck(id, message) {
271
+ return { id, status: "SKIP", message };
272
+ }
273
+ //# sourceMappingURL=run-onboarding.js.map