@companyhelm/cli 0.4.1 → 0.4.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 (124) hide show
  1. package/dist/cli_io_interface.d.ts +10 -0
  2. package/dist/cli_io_interface.js +2 -0
  3. package/dist/cli_io_interface.js.map +1 -0
  4. package/dist/companyhelm_cli.d.ts +20 -0
  5. package/dist/companyhelm_cli.js +73 -0
  6. package/dist/companyhelm_cli.js.map +1 -0
  7. package/dist/console_io.d.ts +9 -0
  8. package/dist/console_io.js +13 -0
  9. package/dist/console_io.js.map +1 -0
  10. package/dist/index.d.ts +2 -0
  11. package/dist/index.js +4 -0
  12. package/dist/index.js.map +1 -0
  13. package/package.json +20 -29
  14. package/LICENSE +0 -21
  15. package/README.md +0 -66
  16. package/dist/cli.d.ts +0 -2
  17. package/dist/cli.js +0 -39
  18. package/dist/commands/dependencies.d.ts +0 -28
  19. package/dist/commands/dependencies.js +0 -292
  20. package/dist/commands/down.d.ts +0 -3
  21. package/dist/commands/down.js +0 -5
  22. package/dist/commands/interactive.d.ts +0 -7
  23. package/dist/commands/interactive.js +0 -25
  24. package/dist/commands/logs.d.ts +0 -3
  25. package/dist/commands/logs.js +0 -14
  26. package/dist/commands/register-commands.d.ts +0 -3
  27. package/dist/commands/register-commands.js +0 -23
  28. package/dist/commands/reset.d.ts +0 -7
  29. package/dist/commands/reset.js +0 -51
  30. package/dist/commands/set-image-version.d.ts +0 -31
  31. package/dist/commands/set-image-version.js +0 -87
  32. package/dist/commands/setup-github-app.d.ts +0 -13
  33. package/dist/commands/setup-github-app.js +0 -233
  34. package/dist/commands/startup-preferences.d.ts +0 -3
  35. package/dist/commands/startup-preferences.js +0 -39
  36. package/dist/commands/status.d.ts +0 -3
  37. package/dist/commands/status.js +0 -7
  38. package/dist/commands/up.d.ts +0 -3
  39. package/dist/commands/up.js +0 -39
  40. package/dist/config/image_config.d.ts +0 -4
  41. package/dist/config/image_config.js +0 -4
  42. package/dist/core/bootstrap/DeploymentBootstrapper.d.ts +0 -15
  43. package/dist/core/bootstrap/DeploymentBootstrapper.js +0 -118
  44. package/dist/core/bootstrap/SeedSqlRenderer.d.ts +0 -12
  45. package/dist/core/bootstrap/SeedSqlRenderer.js +0 -44
  46. package/dist/core/config/ApiEnvFileWriter.d.ts +0 -8
  47. package/dist/core/config/ApiEnvFileWriter.js +0 -33
  48. package/dist/core/config/GithubAppConfig.d.ts +0 -6
  49. package/dist/core/config/GithubAppConfig.js +0 -26
  50. package/dist/core/config/GithubAppConfigStore.d.ts +0 -11
  51. package/dist/core/config/GithubAppConfigStore.js +0 -57
  52. package/dist/core/docker/ComposeTemplateRenderer.d.ts +0 -22
  53. package/dist/core/docker/ComposeTemplateRenderer.js +0 -66
  54. package/dist/core/docker/DockerStackManager.d.ts +0 -29
  55. package/dist/core/docker/DockerStackManager.js +0 -163
  56. package/dist/core/local/ApiLocalService.d.ts +0 -22
  57. package/dist/core/local/ApiLocalService.js +0 -65
  58. package/dist/core/local/LocalRepoSourceResolver.d.ts +0 -24
  59. package/dist/core/local/LocalRepoSourceResolver.js +0 -33
  60. package/dist/core/local/LocalServiceProcessManager.d.ts +0 -18
  61. package/dist/core/local/LocalServiceProcessManager.js +0 -83
  62. package/dist/core/local/WebLocalService.d.ts +0 -23
  63. package/dist/core/local/WebLocalService.js +0 -101
  64. package/dist/core/logs/LogsService.d.ts +0 -6
  65. package/dist/core/logs/LogsService.js +0 -14
  66. package/dist/core/process/CommandRunner.d.ts +0 -4
  67. package/dist/core/process/CommandRunner.js +0 -51
  68. package/dist/core/runner/RunnerSupervisor.d.ts +0 -29
  69. package/dist/core/runner/RunnerSupervisor.js +0 -90
  70. package/dist/core/runner/runner-bootstrap.d.ts +0 -2
  71. package/dist/core/runner/runner-bootstrap.js +0 -48
  72. package/dist/core/runtime/CliPackageMetadata.d.ts +0 -3
  73. package/dist/core/runtime/CliPackageMetadata.js +0 -8
  74. package/dist/core/runtime/CliRoot.d.ts +0 -2
  75. package/dist/core/runtime/CliRoot.js +0 -23
  76. package/dist/core/runtime/ImageCatalog.d.ts +0 -11
  77. package/dist/core/runtime/ImageCatalog.js +0 -16
  78. package/dist/core/runtime/ImageConfigStore.d.ts +0 -15
  79. package/dist/core/runtime/ImageConfigStore.js +0 -51
  80. package/dist/core/runtime/LocalConfigStore.d.ts +0 -16
  81. package/dist/core/runtime/LocalConfigStore.js +0 -50
  82. package/dist/core/runtime/ManagedImages.d.ts +0 -10
  83. package/dist/core/runtime/ManagedImages.js +0 -27
  84. package/dist/core/runtime/PortAllocator.d.ts +0 -9
  85. package/dist/core/runtime/PortAllocator.js +0 -20
  86. package/dist/core/runtime/PublicImageTagRegistry.d.ts +0 -17
  87. package/dist/core/runtime/PublicImageTagRegistry.js +0 -168
  88. package/dist/core/runtime/RuntimePaths.d.ts +0 -16
  89. package/dist/core/runtime/RuntimePaths.js +0 -43
  90. package/dist/core/runtime/RuntimeState.d.ts +0 -38
  91. package/dist/core/runtime/RuntimeState.js +0 -1
  92. package/dist/core/runtime/RuntimeStateStore.d.ts +0 -11
  93. package/dist/core/runtime/RuntimeStateStore.js +0 -81
  94. package/dist/core/runtime/Secrets.d.ts +0 -10
  95. package/dist/core/runtime/Secrets.js +0 -26
  96. package/dist/core/runtime/VersionCatalog.d.ts +0 -10
  97. package/dist/core/runtime/VersionCatalog.js +0 -21
  98. package/dist/core/services/ManagedServiceNames.d.ts +0 -5
  99. package/dist/core/services/ManagedServiceNames.js +0 -12
  100. package/dist/core/status/StatusService.d.ts +0 -19
  101. package/dist/core/status/StatusService.js +0 -30
  102. package/dist/core/ui/TerminalRenderer.d.ts +0 -17
  103. package/dist/core/ui/TerminalRenderer.js +0 -71
  104. package/dist/preflight/ApiPortPreflightCheck.d.ts +0 -6
  105. package/dist/preflight/ApiPortPreflightCheck.js +0 -10
  106. package/dist/preflight/DockerInstalledPreflightCheck.d.ts +0 -7
  107. package/dist/preflight/DockerInstalledPreflightCheck.js +0 -15
  108. package/dist/preflight/PortAvailabilityPreflightCheck.d.ts +0 -7
  109. package/dist/preflight/PortAvailabilityPreflightCheck.js +0 -31
  110. package/dist/preflight/PostgresPortPreflightCheck.d.ts +0 -6
  111. package/dist/preflight/PostgresPortPreflightCheck.js +0 -10
  112. package/dist/preflight/PreflightCheck.d.ts +0 -3
  113. package/dist/preflight/PreflightCheck.js +0 -1
  114. package/dist/preflight/WebPortPreflightCheck.d.ts +0 -6
  115. package/dist/preflight/WebPortPreflightCheck.js +0 -10
  116. package/dist/preflight/runStartupPreflightChecks.d.ts +0 -18
  117. package/dist/preflight/runStartupPreflightChecks.js +0 -42
  118. package/dist/templates/api.env.tpl +0 -3
  119. package/dist/templates/docker-compose.yaml.tpl +0 -24
  120. package/dist/templates/seed.sql.tpl +0 -76
  121. package/src/config/image_config.ts +0 -4
  122. package/src/templates/api.env.tpl +0 -3
  123. package/src/templates/docker-compose.yaml.tpl +0 -24
  124. package/src/templates/seed.sql.tpl +0 -76
@@ -1,292 +0,0 @@
1
- import fs from "node:fs";
2
- import { DeploymentBootstrapper } from "../core/bootstrap/DeploymentBootstrapper.js";
3
- import { ApiEnvFileWriter } from "../core/config/ApiEnvFileWriter.js";
4
- import { GithubAppConfigStore } from "../core/config/GithubAppConfigStore.js";
5
- import { DockerStackManager } from "../core/docker/DockerStackManager.js";
6
- import { ApiLocalService } from "../core/local/ApiLocalService.js";
7
- import { LocalRepoSourceResolver } from "../core/local/LocalRepoSourceResolver.js";
8
- import { LocalServiceProcessManager } from "../core/local/LocalServiceProcessManager.js";
9
- import { WebLocalService } from "../core/local/WebLocalService.js";
10
- import { LogsService } from "../core/logs/LogsService.js";
11
- import { CommandRunner } from "../core/process/CommandRunner.js";
12
- import { RunnerSupervisor } from "../core/runner/RunnerSupervisor.js";
13
- import { defaultCliRoot } from "../core/runtime/CliRoot.js";
14
- import { createPasswordHash } from "../core/runtime/Secrets.js";
15
- import { RuntimePaths } from "../core/runtime/RuntimePaths.js";
16
- import { RuntimeStateStore } from "../core/runtime/RuntimeStateStore.js";
17
- import { VersionCatalog } from "../core/runtime/VersionCatalog.js";
18
- import { StatusService } from "../core/status/StatusService.js";
19
- import { TerminalRenderer } from "../core/ui/TerminalRenderer.js";
20
- import { LocalConfigStore } from "../core/runtime/LocalConfigStore.js";
21
- import { PortAllocator } from "../core/runtime/PortAllocator.js";
22
- import { runStartupPreflightChecks } from "../preflight/runStartupPreflightChecks.js";
23
- import { ensureGithubAppConfig } from "./setup-github-app.js";
24
- import { ensureAgentWorkspaceMode } from "./startup-preferences.js";
25
- function runtimeRoot() {
26
- return defaultCliRoot();
27
- }
28
- export function createDefaultDependencies() {
29
- const root = runtimeRoot();
30
- const stateStore = new RuntimeStateStore(root);
31
- const runtimePaths = new RuntimePaths(root);
32
- const commandRunner = new CommandRunner();
33
- const renderer = new TerminalRenderer(process.stdout.isTTY);
34
- const dockerStackManager = new DockerStackManager(root, commandRunner);
35
- const runnerSupervisor = new RunnerSupervisor(runtimePaths.runnerConfigPath());
36
- const bootstrapper = new DeploymentBootstrapper();
37
- const githubAppConfigStore = new GithubAppConfigStore();
38
- const apiEnvFileWriter = new ApiEnvFileWriter(root);
39
- const localRepoSourceResolver = new LocalRepoSourceResolver(process.cwd());
40
- const localConfigStore = new LocalConfigStore();
41
- const localServiceProcessManager = new LocalServiceProcessManager();
42
- const apiLocalService = new ApiLocalService(localServiceProcessManager, commandRunner);
43
- const webLocalService = new WebLocalService(localServiceProcessManager, commandRunner);
44
- const versionCatalog = new VersionCatalog();
45
- const statusService = new StatusService(() => dockerStackManager.runningServices(), {
46
- api: () => {
47
- const state = stateStore.load();
48
- return state?.services.api.source === "local"
49
- ? localServiceProcessManager.isRunning(state.services.api)
50
- : undefined;
51
- },
52
- frontend: () => {
53
- const state = stateStore.load();
54
- return state?.services.frontend.source === "local"
55
- ? localServiceProcessManager.isRunning(state.services.frontend)
56
- : undefined;
57
- },
58
- runner: async () => {
59
- try {
60
- const statusCommand = runnerSupervisor.buildStatusArgs();
61
- const output = await commandRunner.capture(statusCommand.command, statusCommand.args);
62
- return output.includes("Daemon: running");
63
- }
64
- catch {
65
- return false;
66
- }
67
- }
68
- });
69
- const logsService = new LogsService(async (service) => {
70
- if (service === "runner") {
71
- if (fs.existsSync(runtimePaths.runnerLogPath())) {
72
- process.stdout.write(fs.readFileSync(runtimePaths.runnerLogPath(), "utf8"));
73
- }
74
- return;
75
- }
76
- const state = stateStore.load();
77
- if (service === "api" && state?.services.api.source === "local") {
78
- localServiceProcessManager.printLogs(state.services.api);
79
- return;
80
- }
81
- if (service === "frontend" && state?.services.frontend.source === "local") {
82
- localServiceProcessManager.printLogs(state.services.frontend);
83
- return;
84
- }
85
- await dockerStackManager.logs(service);
86
- });
87
- return {
88
- async up(options = {}) {
89
- const logLevel = options.logLevel ?? "info";
90
- const useHostDockerRuntime = options.useHostDockerRuntime ?? false;
91
- process.stdout.write(`${renderer.renderBanner()}\n`);
92
- const desiredSources = localRepoSourceResolver.resolve(options);
93
- const currentState = stateStore.load();
94
- const allocatedPorts = currentState?.ports ?? new PortAllocator().allocate();
95
- await runStartupPreflightChecks({
96
- commandRunner,
97
- currentState,
98
- desiredSources,
99
- ports: allocatedPorts,
100
- readStatus: () => statusService.read()
101
- });
102
- const workspaceMode = await ensureAgentWorkspaceMode(localConfigStore, process.stdin, process.stdout);
103
- const githubAppConfig = await ensureGithubAppConfig(githubAppConfigStore, process.stdin, process.stdout, { workspaceMode });
104
- const state = currentState ?? stateStore.initialize();
105
- const runnerAlreadyRunning = await isRunnerRunning(commandRunner, runnerSupervisor);
106
- const versions = versionCatalog.resolve();
107
- const passwordRecord = createPasswordHash(state.auth.password);
108
- const startedLocalServices = [];
109
- let runnerStarted = false;
110
- fs.mkdirSync(root, { recursive: true });
111
- fs.mkdirSync(runtimePaths.serviceRuntimePath(), { recursive: true });
112
- apiEnvFileWriter.write(githubAppConfig);
113
- bootstrapper.writeSeedSql(root, state, passwordRecord.passwordHash, passwordRecord.passwordSalt);
114
- bootstrapper.writeApiConfig(root, state, logLevel, {
115
- databaseHost: desiredSources.api.source === "local" ? "127.0.0.1" : "postgres",
116
- githubAppConfig
117
- });
118
- bootstrapper.writeFrontendConfig(root, state);
119
- await stopLocalServicesFromState(stateStore.load(), localServiceProcessManager);
120
- try {
121
- await dockerStackManager.up(state, {
122
- frontendLogLevel: logLevel,
123
- includeApi: desiredSources.api.source === "docker",
124
- includeFrontend: desiredSources.frontend.source === "docker",
125
- exposePostgresPort: desiredSources.api.source === "local"
126
- });
127
- const apiUrl = `http://127.0.0.1:${state.ports.apiHttp}/graphql`;
128
- const uiUrl = `http://127.0.0.1:${state.ports.ui}`;
129
- if (desiredSources.api.source === "local") {
130
- process.stdout.write(`${renderer.progress(`Starting companyhelm-api from ${desiredSources.api.repoPath}...`)}\n`);
131
- state.services.api = await apiLocalService.start({
132
- repoPath: desiredSources.api.repoPath,
133
- configPath: runtimePaths.apiConfigPath(),
134
- graphqlUrl: apiUrl,
135
- logPath: runtimePaths.serviceLogPath("api"),
136
- githubAppConfig,
137
- state,
138
- logLevel
139
- });
140
- startedLocalServices.push("api");
141
- }
142
- else {
143
- state.services.api = { source: "docker" };
144
- }
145
- process.stdout.write(`${renderer.progress("Initializing the database...")}\n`);
146
- process.stdout.write(`${renderer.progress("Waiting for database migrations...")}\n`);
147
- await dockerStackManager.applySeedSql(state.auth.username);
148
- if (runnerAlreadyRunning) {
149
- process.stdout.write(`${renderer.progress("Runner already running; skipping startup.")}\n`);
150
- }
151
- else {
152
- const configureSdkCommand = runnerSupervisor.buildUseHostAuthArgs();
153
- process.stdout.write(`${renderer.progress("Configuring runner authentication...")}\n`);
154
- await commandRunner.run(configureSdkCommand.command, configureSdkCommand.args);
155
- const startCommand = runnerSupervisor.buildStartArgs({
156
- serverUrl: `127.0.0.1:${state.ports.runnerGrpc}`,
157
- agentApiUrl: `http://127.0.0.1:${state.ports.apiHttp}/agent/v1`,
158
- logPath: runtimePaths.runnerLogPath(),
159
- secret: state.runner.secret,
160
- logLevel,
161
- useHostDockerRuntime,
162
- workspaceMode,
163
- projectRoot: process.cwd()
164
- });
165
- process.stdout.write(`${renderer.progress("Starting the runner...")}\n`);
166
- await commandRunner.run(startCommand.command, startCommand.args, undefined, startCommand.env);
167
- runnerStarted = true;
168
- }
169
- if (desiredSources.frontend.source === "local") {
170
- process.stdout.write(`${renderer.progress(`Starting companyhelm-web from ${desiredSources.frontend.repoPath}...`)}\n`);
171
- state.services.frontend = await webLocalService.start({
172
- repoPath: desiredSources.frontend.repoPath,
173
- configPath: runtimePaths.frontendConfigPath(),
174
- url: uiUrl,
175
- uiPort: state.ports.ui,
176
- logPath: runtimePaths.serviceLogPath("frontend"),
177
- logLevel
178
- });
179
- startedLocalServices.push("frontend");
180
- }
181
- else {
182
- state.services.frontend = { source: "docker" };
183
- }
184
- stateStore.persist(state);
185
- process.stdout.write(`${renderer.success(`API ready: ${apiUrl}`)}\n`);
186
- process.stdout.write(`CompanyHelm CLI: ${versions.cliPackage}\n`);
187
- process.stdout.write(`Runner package: ${versions.runnerPackage}\n`);
188
- process.stdout.write(desiredSources.api.source === "local"
189
- ? `API repo: ${desiredSources.api.repoPath}\n`
190
- : `API image: ${versions.images.api}\n`);
191
- process.stdout.write(desiredSources.frontend.source === "local"
192
- ? `companyhelm-web repo: ${desiredSources.frontend.repoPath}\n`
193
- : `companyhelm-web image: ${versions.images.frontend}\n`);
194
- process.stdout.write(`Postgres image: ${versions.images.postgres}\n`);
195
- process.stdout.write(`\n${renderer.success("CompanyHelm started successfully.")}\n`);
196
- process.stdout.write(`${renderer.successHighlight("UI URL")}\n`);
197
- process.stdout.write(`${renderer.clickableUrl(uiUrl)}\n`);
198
- process.stdout.write(`${renderer.successHighlight("Login credentials")}\n`);
199
- process.stdout.write(`username: ${state.auth.username}\n`);
200
- process.stdout.write(`password: ${state.auth.password}\n`);
201
- }
202
- catch (error) {
203
- if (runnerStarted) {
204
- const stopCommand = runnerSupervisor.buildStopArgs();
205
- try {
206
- await commandRunner.run(stopCommand.command, stopCommand.args);
207
- }
208
- catch {
209
- // Ignore runner stop failures during cleanup.
210
- }
211
- }
212
- for (const service of startedLocalServices.reverse()) {
213
- const runtime = service === "api" ? state.services.api : state.services.frontend;
214
- if (runtime.source === "local") {
215
- await localServiceProcessManager.stop(runtime);
216
- }
217
- }
218
- await dockerStackManager.down();
219
- throw error;
220
- }
221
- },
222
- async down() {
223
- const stopCommand = runnerSupervisor.buildStopArgs();
224
- try {
225
- await commandRunner.run(stopCommand.command, stopCommand.args);
226
- }
227
- catch {
228
- // Ignore runner stop failures during teardown so container cleanup still happens.
229
- }
230
- const state = stateStore.load();
231
- if (!state) {
232
- return;
233
- }
234
- await stopLocalServicesFromState(state, localServiceProcessManager);
235
- await dockerStackManager.down();
236
- },
237
- async status() {
238
- const services = await statusService.read();
239
- const state = stateStore.load();
240
- return {
241
- services,
242
- apiUrl: state ? `http://127.0.0.1:${state.ports.apiHttp}/graphql` : undefined,
243
- uiUrl: state ? `http://127.0.0.1:${state.ports.ui}` : undefined,
244
- username: state?.auth.username,
245
- versions: versionCatalog.resolve()
246
- };
247
- },
248
- logs(service) {
249
- return logsService.stream(service);
250
- },
251
- async reset(options = {}) {
252
- const state = stateStore.load();
253
- if (state) {
254
- const stopCommand = runnerSupervisor.buildStopArgs();
255
- try {
256
- await commandRunner.run(stopCommand.command, stopCommand.args);
257
- }
258
- catch {
259
- // Ignore runner stop failures during teardown so docker cleanup still runs.
260
- }
261
- await stopLocalServicesFromState(state, localServiceProcessManager);
262
- }
263
- await dockerStackManager.down({ removeVolumes: true });
264
- fs.rmSync(localConfigStore.configPath(), { force: true });
265
- fs.rmSync(root, { recursive: true, force: true });
266
- if (options.removeGithubAppConfig) {
267
- githubAppConfigStore.delete();
268
- }
269
- }
270
- };
271
- }
272
- async function stopLocalServicesFromState(state, processManager) {
273
- if (!state) {
274
- return;
275
- }
276
- if (state.services.api.source === "local") {
277
- await processManager.stop(state.services.api);
278
- }
279
- if (state.services.frontend.source === "local") {
280
- await processManager.stop(state.services.frontend);
281
- }
282
- }
283
- async function isRunnerRunning(commandRunner, runnerSupervisor) {
284
- try {
285
- const statusCommand = runnerSupervisor.buildStatusArgs();
286
- const output = await commandRunner.capture(statusCommand.command, statusCommand.args);
287
- return output.includes("Daemon: running");
288
- }
289
- catch (error) {
290
- return false;
291
- }
292
- }
@@ -1,3 +0,0 @@
1
- import type { Command } from "commander";
2
- import type { CommandDependencies } from "./dependencies.js";
3
- export declare function registerDownCommand(program: Command, dependencies: CommandDependencies): void;
@@ -1,5 +0,0 @@
1
- export function registerDownCommand(program, dependencies) {
2
- program.command("down").description("Stop the local deployment.").action(async () => {
3
- await dependencies.down();
4
- });
5
- }
@@ -1,7 +0,0 @@
1
- import type { Readable, Writable } from "node:stream";
2
- export declare class InteractiveCommandCancelledError extends Error {
3
- constructor(message: string);
4
- }
5
- export declare function hasInteractiveTerminal(input: Readable, output: Writable): boolean;
6
- export declare function requireInteractiveTerminal(input: Readable, output: Writable, message: string): void;
7
- export declare function unwrapPromptResult<T>(value: T | symbol, message: string, output: Writable): T;
@@ -1,25 +0,0 @@
1
- import * as clack from "@clack/prompts";
2
- export class InteractiveCommandCancelledError extends Error {
3
- constructor(message) {
4
- super(message);
5
- this.name = "InteractiveCommandCancelledError";
6
- }
7
- }
8
- function isReadableTty(input) {
9
- return "isTTY" in input && Boolean(input.isTTY);
10
- }
11
- export function hasInteractiveTerminal(input, output) {
12
- return isReadableTty(input) && clack.isTTY(output);
13
- }
14
- export function requireInteractiveTerminal(input, output, message) {
15
- if (!hasInteractiveTerminal(input, output)) {
16
- throw new Error(message);
17
- }
18
- }
19
- export function unwrapPromptResult(value, message, output) {
20
- if (clack.isCancel(value)) {
21
- clack.cancel(message, { output });
22
- throw new InteractiveCommandCancelledError(message);
23
- }
24
- return value;
25
- }
@@ -1,3 +0,0 @@
1
- import type { Command } from "commander";
2
- import type { CommandDependencies } from "./dependencies.js";
3
- export declare function registerLogsCommand(program: Command, dependencies: CommandDependencies): void;
@@ -1,14 +0,0 @@
1
- import { AVAILABLE_MANAGED_SERVICE_NAMES } from "../core/services/ManagedServiceNames.js";
2
- export function registerLogsCommand(program, dependencies) {
3
- program
4
- .command("logs")
5
- .description("Show logs for a managed service.")
6
- .argument("[service]")
7
- .action(async (service) => {
8
- if (!service) {
9
- process.stdout.write(`Available services:\n${AVAILABLE_MANAGED_SERVICE_NAMES.map((name) => `- ${name}`).join("\n")}\n`);
10
- return;
11
- }
12
- await dependencies.logs(service);
13
- });
14
- }
@@ -1,3 +0,0 @@
1
- import { Command } from "commander";
2
- import { type CommandDependencies } from "./dependencies.js";
3
- export declare function buildProgram(dependencies?: CommandDependencies): Command;
@@ -1,23 +0,0 @@
1
- import { Command } from "commander";
2
- import { createDefaultDependencies } from "./dependencies.js";
3
- import { CliPackageMetadata } from "../core/runtime/CliPackageMetadata.js";
4
- import { registerDownCommand } from "./down.js";
5
- import { registerLogsCommand } from "./logs.js";
6
- import { registerResetCommand } from "./reset.js";
7
- import { registerSetupGithubAppCommand } from "./setup-github-app.js";
8
- import { registerSetImageVersionCommand } from "./set-image-version.js";
9
- import { registerStatusCommand } from "./status.js";
10
- import { registerUpCommand } from "./up.js";
11
- export function buildProgram(dependencies = createDefaultDependencies()) {
12
- const program = new Command()
13
- .name("companyhelm")
14
- .version(new CliPackageMetadata().version());
15
- registerSetupGithubAppCommand(program);
16
- registerUpCommand(program, dependencies);
17
- registerDownCommand(program, dependencies);
18
- registerStatusCommand(program, dependencies);
19
- registerLogsCommand(program, dependencies);
20
- registerSetImageVersionCommand(program);
21
- registerResetCommand(program, dependencies);
22
- return program;
23
- }
@@ -1,7 +0,0 @@
1
- import type { Readable, Writable } from "node:stream";
2
- import type { Command } from "commander";
3
- import { GithubAppConfigStore } from "../core/config/GithubAppConfigStore.js";
4
- import type { CommandDependencies } from "./dependencies.js";
5
- export declare function confirmReset(input?: Readable, output?: Writable): Promise<boolean>;
6
- export declare function confirmRemoveGithubAppConfig(store?: GithubAppConfigStore, input?: Readable, output?: Writable): Promise<boolean>;
7
- export declare function registerResetCommand(program: Command, dependencies: CommandDependencies): void;
@@ -1,51 +0,0 @@
1
- import * as clack from "@clack/prompts";
2
- import { GithubAppConfigStore } from "../core/config/GithubAppConfigStore.js";
3
- import { requireInteractiveTerminal, unwrapPromptResult } from "./interactive.js";
4
- export async function confirmReset(input = process.stdin, output = process.stdout) {
5
- requireInteractiveTerminal(input, output, "reset requires confirmation from a TTY. Re-run with --yes to skip the prompt.");
6
- const confirmed = await clack.confirm({
7
- message: "This will remove CompanyHelm containers, Postgres data, generated runtime files under ~/.companyhelm/cli/runtime, and the CLI workspace config under ~/.companyhelm/cli/config.yaml. Continue?",
8
- active: "Yes",
9
- inactive: "No",
10
- initialValue: false,
11
- input,
12
- output
13
- });
14
- return unwrapPromptResult(confirmed, "Reset cancelled.", output);
15
- }
16
- export async function confirmRemoveGithubAppConfig(store = new GithubAppConfigStore(), input = process.stdin, output = process.stdout) {
17
- if (!store.hasConfig()) {
18
- return false;
19
- }
20
- requireInteractiveTerminal(input, output, "reset requires confirmation from a TTY. Re-run with --yes to skip the prompt.");
21
- const confirmed = await clack.confirm({
22
- message: `Also remove the machine GitHub App config at ${store.configPath()}?`,
23
- active: "Remove it",
24
- inactive: "Keep it",
25
- initialValue: false,
26
- input,
27
- output
28
- });
29
- return unwrapPromptResult(confirmed, "Reset cancelled.", output);
30
- }
31
- export function registerResetCommand(program, dependencies) {
32
- program
33
- .command("reset")
34
- .description("Destroy the local deployment state.")
35
- .option("-y, --yes", "Skip the confirmation prompt.")
36
- .option("--remove-github-app-config", "Also remove the machine GitHub App config.")
37
- .action(async (options) => {
38
- let removeGithubAppConfig = Boolean(options.removeGithubAppConfig);
39
- if (!options.yes) {
40
- const confirmed = await confirmReset();
41
- if (!confirmed) {
42
- clack.cancel("Reset cancelled.");
43
- return;
44
- }
45
- if (!removeGithubAppConfig) {
46
- removeGithubAppConfig = await confirmRemoveGithubAppConfig();
47
- }
48
- }
49
- await dependencies.reset({ removeGithubAppConfig });
50
- });
51
- }
@@ -1,31 +0,0 @@
1
- import type { Readable, Writable } from "node:stream";
2
- import type { Command } from "commander";
3
- import { type ManagedImageService } from "../core/runtime/ManagedImages.js";
4
- export interface SetImageVersionOptions {
5
- service?: string;
6
- limit: number;
7
- }
8
- export interface AvailableImageTag {
9
- tag: string;
10
- createdAt?: string;
11
- }
12
- export interface InteractiveImageSelector {
13
- listAvailableTags(service: ManagedImageService, limit: number): Promise<AvailableImageTag[]>;
14
- buildImageReference(service: ManagedImageService, tag: string): string;
15
- }
16
- export interface ImageVersionStore {
17
- load(): {
18
- images: Partial<Record<ManagedImageService, string>>;
19
- };
20
- setImage(service: ManagedImageService, image: string): {
21
- configPath: string;
22
- image: string;
23
- };
24
- }
25
- export declare function runSetImageVersion(options: SetImageVersionOptions, dependencies?: {
26
- input?: Readable;
27
- output?: Writable;
28
- registry?: InteractiveImageSelector;
29
- configStore?: ImageVersionStore;
30
- }): Promise<void>;
31
- export declare function registerSetImageVersionCommand(program: Command): void;
@@ -1,87 +0,0 @@
1
- import * as clack from "@clack/prompts";
2
- import { MANAGED_IMAGE_SERVICES, requireManagedImageService } from "../core/runtime/ManagedImages.js";
3
- import { PublicImageTagRegistry } from "../core/runtime/PublicImageTagRegistry.js";
4
- import { ImageConfigStore } from "../core/runtime/ImageConfigStore.js";
5
- import { requireInteractiveTerminal, unwrapPromptResult } from "./interactive.js";
6
- function parsePositiveInteger(value) {
7
- const parsed = Number.parseInt(value, 10);
8
- if (!Number.isInteger(parsed) || parsed < 1) {
9
- throw new Error(`Expected a positive integer, received: ${value}`);
10
- }
11
- return parsed;
12
- }
13
- async function promptForSelection(message, options, input, output, defaultValue) {
14
- requireInteractiveTerminal(input, output, "set-image-version requires a TTY so you can choose an image interactively.");
15
- if (options.length === 0) {
16
- throw new Error("No selectable options were provided.");
17
- }
18
- const selected = await clack.select({
19
- message,
20
- options: options.map((option, index) => ({
21
- ...option,
22
- hint: option.value === defaultValue ? "current" : undefined
23
- })),
24
- initialValue: defaultValue,
25
- input,
26
- output
27
- });
28
- return unwrapPromptResult(selected, "Image selection cancelled.", output);
29
- }
30
- async function loadAvailableTags(registry, service, limit, output) {
31
- const spinner = clack.spinner({ output });
32
- spinner.start(`Loading the latest ${limit} image tags for ${service}`);
33
- let tags;
34
- try {
35
- tags = await registry.listAvailableTags(service, limit);
36
- }
37
- catch (error) {
38
- spinner.stop("Unable to load image tags");
39
- throw error;
40
- }
41
- if (tags.length === 0) {
42
- spinner.stop("No image tags found");
43
- throw new Error(`No image tags found for ${service}.`);
44
- }
45
- spinner.stop(`Loaded ${tags.length} image tag${tags.length === 1 ? "" : "s"}`);
46
- return tags;
47
- }
48
- function formatTagTimestamp(createdAt) {
49
- if (!createdAt) {
50
- return "timestamp unavailable";
51
- }
52
- const timestamp = new Date(createdAt);
53
- if (Number.isNaN(timestamp.valueOf())) {
54
- return "timestamp unavailable";
55
- }
56
- return timestamp.toISOString().slice(0, 16).replace("T", " ") + " UTC";
57
- }
58
- export async function runSetImageVersion(options, dependencies = {}) {
59
- const input = dependencies.input ?? process.stdin;
60
- const output = dependencies.output ?? process.stdout;
61
- const registry = dependencies.registry ?? new PublicImageTagRegistry();
62
- const configStore = dependencies.configStore ?? new ImageConfigStore();
63
- clack.intro("CompanyHelm image selection", { output });
64
- const selectedService = options.service
65
- ? requireManagedImageService(options.service)
66
- : await promptForSelection("Which image do you want to pin?", MANAGED_IMAGE_SERVICES.map((service) => ({ value: service, label: service })), input, output).then((value) => requireManagedImageService(value));
67
- const currentImage = configStore.load().images[selectedService];
68
- clack.log.info(`Current configured image for ${selectedService}: ${currentImage ?? "default (latest)"}`, { output });
69
- const tags = await loadAvailableTags(registry, selectedService, options.limit, output);
70
- const currentTag = currentImage ? currentImage.slice(currentImage.lastIndexOf(":") + 1) : undefined;
71
- const selectedTag = await promptForSelection(`Choose the ${selectedService} image tag`, tags.map((tag) => ({
72
- value: tag.tag,
73
- label: `${tag.tag} (${formatTagTimestamp(tag.createdAt)})`
74
- })), input, output, currentTag);
75
- const result = configStore.setImage(selectedService, registry.buildImageReference(selectedService, selectedTag));
76
- clack.outro(`Updated ${result.configPath} to ${result.image}`, { output });
77
- }
78
- export function registerSetImageVersionCommand(program) {
79
- program
80
- .command("set-image-version")
81
- .description("Interactively choose an API or frontend image tag and store it in the packaged image config.")
82
- .option("-s, --service <service>", "Prefill the service to update (api or frontend)")
83
- .option("-l, --limit <count>", "How many image tags to show", parsePositiveInteger, 20)
84
- .action(async (options) => {
85
- await runSetImageVersion(options);
86
- });
87
- }
@@ -1,13 +0,0 @@
1
- import { Writable, type Readable } from "node:stream";
2
- import type { Command } from "commander";
3
- import { GithubAppConfigStore } from "../core/config/GithubAppConfigStore.js";
4
- import { type GithubAppConfig } from "../core/config/GithubAppConfig.js";
5
- import type { AgentWorkspaceMode } from "../core/runtime/LocalConfigStore.js";
6
- type BrowserUrlOpener = (url: string) => Promise<void>;
7
- export declare function readPemFromTerminal(input?: Readable, output?: Writable): Promise<string>;
8
- export declare function promptGithubAppConfig(input?: Readable, output?: Writable, openBrowser?: BrowserUrlOpener): Promise<GithubAppConfig>;
9
- export declare function ensureGithubAppConfig(store?: GithubAppConfigStore, input?: Readable, output?: Writable, options?: {
10
- workspaceMode?: AgentWorkspaceMode;
11
- }): Promise<GithubAppConfig | null>;
12
- export declare function registerSetupGithubAppCommand(program: Command, store?: GithubAppConfigStore): void;
13
- export {};