cyrus-docker 0.1.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 (91) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +245 -0
  3. package/dist/Application.d.ts +64 -0
  4. package/dist/Application.d.ts.map +1 -0
  5. package/dist/Application.js +104 -0
  6. package/dist/Application.js.map +1 -0
  7. package/dist/app.d.ts +3 -0
  8. package/dist/app.d.ts.map +1 -0
  9. package/dist/app.js +150 -0
  10. package/dist/app.js.map +1 -0
  11. package/dist/commands/AddRepoCommand.d.ts +11 -0
  12. package/dist/commands/AddRepoCommand.d.ts.map +1 -0
  13. package/dist/commands/AddRepoCommand.js +45 -0
  14. package/dist/commands/AddRepoCommand.js.map +1 -0
  15. package/dist/commands/AuthCommand.d.ts +16 -0
  16. package/dist/commands/AuthCommand.d.ts.map +1 -0
  17. package/dist/commands/AuthCommand.js +85 -0
  18. package/dist/commands/AuthCommand.js.map +1 -0
  19. package/dist/commands/BuildCommand.d.ts +21 -0
  20. package/dist/commands/BuildCommand.d.ts.map +1 -0
  21. package/dist/commands/BuildCommand.js +65 -0
  22. package/dist/commands/BuildCommand.js.map +1 -0
  23. package/dist/commands/ICommand.d.ts +37 -0
  24. package/dist/commands/ICommand.d.ts.map +1 -0
  25. package/dist/commands/ICommand.js +46 -0
  26. package/dist/commands/ICommand.js.map +1 -0
  27. package/dist/commands/InitCommand.d.ts +21 -0
  28. package/dist/commands/InitCommand.d.ts.map +1 -0
  29. package/dist/commands/InitCommand.js +209 -0
  30. package/dist/commands/InitCommand.js.map +1 -0
  31. package/dist/commands/LogsCommand.d.ts +11 -0
  32. package/dist/commands/LogsCommand.d.ts.map +1 -0
  33. package/dist/commands/LogsCommand.js +35 -0
  34. package/dist/commands/LogsCommand.js.map +1 -0
  35. package/dist/commands/ShellCommand.d.ts +8 -0
  36. package/dist/commands/ShellCommand.d.ts.map +1 -0
  37. package/dist/commands/ShellCommand.js +30 -0
  38. package/dist/commands/ShellCommand.js.map +1 -0
  39. package/dist/commands/StartCommand.d.ts +19 -0
  40. package/dist/commands/StartCommand.d.ts.map +1 -0
  41. package/dist/commands/StartCommand.js +147 -0
  42. package/dist/commands/StartCommand.js.map +1 -0
  43. package/dist/commands/StatusCommand.d.ts +8 -0
  44. package/dist/commands/StatusCommand.d.ts.map +1 -0
  45. package/dist/commands/StatusCommand.js +89 -0
  46. package/dist/commands/StatusCommand.js.map +1 -0
  47. package/dist/commands/StopCommand.d.ts +8 -0
  48. package/dist/commands/StopCommand.d.ts.map +1 -0
  49. package/dist/commands/StopCommand.js +45 -0
  50. package/dist/commands/StopCommand.js.map +1 -0
  51. package/dist/commands/ToolsCommand.d.ts +18 -0
  52. package/dist/commands/ToolsCommand.d.ts.map +1 -0
  53. package/dist/commands/ToolsCommand.js +158 -0
  54. package/dist/commands/ToolsCommand.js.map +1 -0
  55. package/dist/config/constants.d.ts +38 -0
  56. package/dist/config/constants.d.ts.map +1 -0
  57. package/dist/config/constants.js +100 -0
  58. package/dist/config/constants.js.map +1 -0
  59. package/dist/config/types.d.ts +142 -0
  60. package/dist/config/types.d.ts.map +1 -0
  61. package/dist/config/types.js +2 -0
  62. package/dist/config/types.js.map +1 -0
  63. package/dist/services/DockerService.d.ts +119 -0
  64. package/dist/services/DockerService.d.ts.map +1 -0
  65. package/dist/services/DockerService.js +371 -0
  66. package/dist/services/DockerService.js.map +1 -0
  67. package/dist/services/Logger.d.ts +64 -0
  68. package/dist/services/Logger.d.ts.map +1 -0
  69. package/dist/services/Logger.js +118 -0
  70. package/dist/services/Logger.js.map +1 -0
  71. package/dist/services/StateService.d.ts +68 -0
  72. package/dist/services/StateService.d.ts.map +1 -0
  73. package/dist/services/StateService.js +137 -0
  74. package/dist/services/StateService.js.map +1 -0
  75. package/dist/services/ToolConfigService.d.ts +66 -0
  76. package/dist/services/ToolConfigService.d.ts.map +1 -0
  77. package/dist/services/ToolConfigService.js +201 -0
  78. package/dist/services/ToolConfigService.js.map +1 -0
  79. package/dist/services/TunnelService.d.ts +43 -0
  80. package/dist/services/TunnelService.d.ts.map +1 -0
  81. package/dist/services/TunnelService.js +129 -0
  82. package/dist/services/TunnelService.js.map +1 -0
  83. package/docker/.env.docker +73 -0
  84. package/docker/.env.docker.example +71 -0
  85. package/docker/Dockerfile +62 -0
  86. package/docker/Dockerfile.custom +18 -0
  87. package/docker/Dockerfile.dev +78 -0
  88. package/docker/docker-compose.yml +59 -0
  89. package/docker/entrypoint.sh +209 -0
  90. package/docker/healthcheck.sh +23 -0
  91. package/package.json +75 -0
@@ -0,0 +1,209 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import inquirer from "inquirer";
3
+ import { ToolConfigService } from "../services/ToolConfigService.js";
4
+ import { BaseCommand } from "./ICommand.js";
5
+ /**
6
+ * Interactive setup wizard for cyrus-docker
7
+ * Prompts for credentials and creates .env.docker
8
+ */
9
+ export class InitCommand extends BaseCommand {
10
+ async execute() {
11
+ this.logger.header("Cyrus Docker Setup");
12
+ // Check prerequisites
13
+ const prereqs = await this.app.checkPrerequisites();
14
+ this.app.printPrerequisiteStatus(prereqs);
15
+ if (!this.app.allPrerequisitesMet(prereqs)) {
16
+ this.app.printMissingPrerequisites(prereqs);
17
+ this.logger.blank();
18
+ this.logger.warn("Please install missing prerequisites and run init again.");
19
+ process.exit(1);
20
+ }
21
+ this.logger.success("All prerequisites met!");
22
+ this.logger.blank();
23
+ // Check if .env.docker already exists
24
+ if (this.app.docker.hasEnvFile()) {
25
+ const { overwrite } = await inquirer.prompt([
26
+ {
27
+ type: "confirm",
28
+ name: "overwrite",
29
+ message: "Configuration file already exists. Do you want to overwrite it?",
30
+ default: false,
31
+ },
32
+ ]);
33
+ if (!overwrite) {
34
+ this.logger.info("Keeping existing configuration.");
35
+ return;
36
+ }
37
+ }
38
+ // Collect credentials
39
+ this.logger.info("Please provide your credentials:");
40
+ this.logger.blank();
41
+ const answers = await this.promptForCredentials();
42
+ // Write .env.docker
43
+ this.app.docker.writeEnvFile(answers);
44
+ // Offer to configure container tools
45
+ await this.promptForTools();
46
+ // Print next steps
47
+ this.printNextSteps();
48
+ }
49
+ /**
50
+ * Prompt user for all required and optional credentials
51
+ */
52
+ async promptForCredentials() {
53
+ // First, ask which authentication method to use
54
+ const { authMethod } = await inquirer.prompt([
55
+ {
56
+ type: "list",
57
+ name: "authMethod",
58
+ message: "Which authentication method would you like to use?",
59
+ choices: [
60
+ {
61
+ name: "Anthropic API Key (from console.anthropic.com)",
62
+ value: "anthropic",
63
+ },
64
+ {
65
+ name: "Claude Code OAuth Token (from Claude Code CLI)",
66
+ value: "claude_code",
67
+ },
68
+ ],
69
+ },
70
+ ]);
71
+ // Prompt for the selected auth credential
72
+ const authCredential = authMethod === "anthropic"
73
+ ? await inquirer.prompt([
74
+ {
75
+ type: "password",
76
+ name: "ANTHROPIC_API_KEY",
77
+ message: "Anthropic API Key:",
78
+ mask: "*",
79
+ validate: (input) => input.length > 0 || "API key is required",
80
+ },
81
+ ])
82
+ : await inquirer.prompt([
83
+ {
84
+ type: "password",
85
+ name: "CLAUDE_CODE_OAUTH_TOKEN",
86
+ message: "Claude Code OAuth Token:",
87
+ mask: "*",
88
+ validate: (input) => input.length > 0 || "OAuth token is required",
89
+ },
90
+ ]);
91
+ const answers = await inquirer.prompt([
92
+ // Linear OAuth
93
+ {
94
+ type: "input",
95
+ name: "LINEAR_CLIENT_ID",
96
+ message: "Linear OAuth Client ID (from linear.app/settings/api/applications):",
97
+ validate: (input) => input.length > 0 || "Client ID is required",
98
+ },
99
+ {
100
+ type: "password",
101
+ name: "LINEAR_CLIENT_SECRET",
102
+ message: "Linear OAuth Client Secret:",
103
+ mask: "*",
104
+ validate: (input) => input.length > 0 || "Client Secret is required",
105
+ },
106
+ {
107
+ type: "input",
108
+ name: "LINEAR_WEBHOOK_SECRET",
109
+ message: "Linear Webhook Secret (press Enter to auto-generate):",
110
+ default: () => randomBytes(32).toString("hex"),
111
+ },
112
+ // ngrok (optional)
113
+ {
114
+ type: "password",
115
+ name: "NGROK_AUTHTOKEN",
116
+ message: "ngrok Authtoken (optional, from dashboard.ngrok.com):",
117
+ mask: "*",
118
+ },
119
+ // Git Configuration
120
+ {
121
+ type: "input",
122
+ name: "GIT_USER_NAME",
123
+ message: "Git user name (for commits):",
124
+ },
125
+ {
126
+ type: "input",
127
+ name: "GIT_USER_EMAIL",
128
+ message: "Git user email (for commits):",
129
+ },
130
+ // GitHub Token (optional)
131
+ {
132
+ type: "password",
133
+ name: "GITHUB_TOKEN",
134
+ message: "GitHub Personal Access Token (optional, for private repos):",
135
+ mask: "*",
136
+ },
137
+ ]);
138
+ return {
139
+ ...authCredential,
140
+ ...answers,
141
+ LINEAR_DIRECT_WEBHOOKS: "true",
142
+ CYRUS_SERVER_PORT: "3456",
143
+ };
144
+ }
145
+ /**
146
+ * Prompt user to optionally configure container tools
147
+ */
148
+ async promptForTools() {
149
+ this.logger.blank();
150
+ const { configureTools } = await inquirer.prompt([
151
+ {
152
+ type: "confirm",
153
+ name: "configureTools",
154
+ message: "Would you like to configure container development tools?",
155
+ default: false,
156
+ },
157
+ ]);
158
+ if (!configureTools) {
159
+ return;
160
+ }
161
+ const toolConfigService = new ToolConfigService(this.logger);
162
+ const presets = toolConfigService.getAvailablePresets();
163
+ // Prompt for presets
164
+ const { selectedPresets } = await inquirer.prompt([
165
+ {
166
+ type: "checkbox",
167
+ name: "selectedPresets",
168
+ message: "Select tool presets to install:",
169
+ choices: presets.map((p) => ({
170
+ name: `${p.name} - ${p.description}`,
171
+ value: p.value,
172
+ })),
173
+ },
174
+ ]);
175
+ // Build config if any presets selected
176
+ if (selectedPresets.length > 0) {
177
+ const config = { presets: selectedPresets };
178
+ toolConfigService.writeConfig(config);
179
+ }
180
+ else {
181
+ this.logger.info("No tools selected. You can configure tools later with 'cyrus-docker tools'");
182
+ }
183
+ }
184
+ /**
185
+ * Print next steps after successful init
186
+ */
187
+ printNextSteps() {
188
+ this.logger.blank();
189
+ this.logger.header("Setup Complete!");
190
+ this.logger.blank();
191
+ this.logger.info("Next steps:");
192
+ this.logger.blank();
193
+ this.logger.raw(" 1. Start Cyrus with ngrok tunnel:");
194
+ this.logger.raw(" $ cyrus-docker start");
195
+ this.logger.blank();
196
+ this.logger.raw(" 2. Configure Linear OAuth (use URLs shown after start):");
197
+ this.logger.raw(" - Go to linear.app/settings/api/applications");
198
+ this.logger.raw(" - Set Callback URL and Webhook URL");
199
+ this.logger.blank();
200
+ this.logger.raw(" 3. Run Linear OAuth flow:");
201
+ this.logger.raw(" $ cyrus-docker auth");
202
+ this.logger.blank();
203
+ this.logger.raw(" 4. Add a repository:");
204
+ this.logger.raw(" $ cyrus-docker add-repo https://github.com/your/repo.git");
205
+ this.logger.blank();
206
+ this.logger.info("For more commands, run: cyrus-docker --help");
207
+ }
208
+ }
209
+ //# sourceMappingURL=InitCommand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InitCommand.js","sourceRoot":"","sources":["../../src/commands/InitCommand.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { LogsOptions } from "../config/types.js";
2
+ import { BaseCommand } from "./ICommand.js";
3
+ /**
4
+ * Show container logs
5
+ */
6
+ export declare class LogsCommand extends BaseCommand {
7
+ private options;
8
+ constructor(app: import("../Application.js").Application, options?: LogsOptions);
9
+ execute(): Promise<void>;
10
+ }
11
+ //# sourceMappingURL=LogsCommand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LogsCommand.d.ts","sourceRoot":"","sources":["../../src/commands/LogsCommand.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C;;GAEG;AACH,qBAAa,WAAY,SAAQ,WAAW;IAG1C,OAAO,CAAC,OAAO;gBADf,GAAG,EAAE,OAAO,mBAAmB,EAAE,WAAW,EACpC,OAAO,GAAE,WAAgB;IAK5B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CA0B9B"}
@@ -0,0 +1,35 @@
1
+ import { DEFAULT_LOG_LINES } from "../config/constants.js";
2
+ import { BaseCommand } from "./ICommand.js";
3
+ /**
4
+ * Show container logs
5
+ */
6
+ export class LogsCommand extends BaseCommand {
7
+ options;
8
+ constructor(app, options = {}) {
9
+ super(app);
10
+ this.options = options;
11
+ }
12
+ async execute() {
13
+ // Check if container is running
14
+ const status = await this.app.docker.getStatus();
15
+ if (!status.running) {
16
+ this.exitWithError("Container is not running. Start it with: cyrus-docker start");
17
+ }
18
+ const { follow = false, lines = DEFAULT_LOG_LINES } = this.options;
19
+ if (follow) {
20
+ this.logger.info("Following container logs (Ctrl+C to stop)...");
21
+ this.logger.divider();
22
+ }
23
+ try {
24
+ await this.app.docker.logs({ follow, lines });
25
+ }
26
+ catch {
27
+ // User pressed Ctrl+C during follow
28
+ if (follow) {
29
+ this.logger.blank();
30
+ this.logger.info("Stopped following logs.");
31
+ }
32
+ }
33
+ }
34
+ }
35
+ //# sourceMappingURL=LogsCommand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LogsCommand.js","sourceRoot":"","sources":["../../src/commands/LogsCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C;;GAEG;AACH,MAAM,OAAO,WAAY,SAAQ,WAAW;IAGlC;IAFT,YACC,GAA4C,EACpC,UAAuB,EAAE;QAEjC,KAAK,CAAC,GAAG,CAAC,CAAC;QAFH,YAAO,GAAP,OAAO,CAAkB;IAGlC,CAAC;IAED,KAAK,CAAC,OAAO;QACZ,gCAAgC;QAChC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACjD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACrB,IAAI,CAAC,aAAa,CACjB,6DAA6D,CAC7D,CAAC;QACH,CAAC;QAED,MAAM,EAAE,MAAM,GAAG,KAAK,EAAE,KAAK,GAAG,iBAAiB,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QAEnE,IAAI,MAAM,EAAE,CAAC;YACZ,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;YACjE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACvB,CAAC;QAED,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QAC/C,CAAC;QAAC,MAAM,CAAC;YACR,oCAAoC;YACpC,IAAI,MAAM,EAAE,CAAC;gBACZ,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;gBACpB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;YAC7C,CAAC;QACF,CAAC;IACF,CAAC;CACD"}
@@ -0,0 +1,8 @@
1
+ import { BaseCommand } from "./ICommand.js";
2
+ /**
3
+ * Open interactive shell in the container
4
+ */
5
+ export declare class ShellCommand extends BaseCommand {
6
+ execute(): Promise<void>;
7
+ }
8
+ //# sourceMappingURL=ShellCommand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ShellCommand.d.ts","sourceRoot":"","sources":["../../src/commands/ShellCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C;;GAEG;AACH,qBAAa,YAAa,SAAQ,WAAW;IACtC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CA2B9B"}
@@ -0,0 +1,30 @@
1
+ import { BaseCommand } from "./ICommand.js";
2
+ /**
3
+ * Open interactive shell in the container
4
+ */
5
+ export class ShellCommand extends BaseCommand {
6
+ async execute() {
7
+ // Check if container is running
8
+ const status = await this.app.docker.getStatus();
9
+ if (!status.running) {
10
+ this.exitWithError("Container is not running. Start it with: cyrus-docker start");
11
+ }
12
+ this.logger.info("Opening shell in container...");
13
+ this.logger.info("Type 'exit' to leave the shell.");
14
+ this.logger.divider();
15
+ try {
16
+ await this.app.docker.shell();
17
+ }
18
+ catch (error) {
19
+ // Check if it was just an exit
20
+ const exitError = error;
21
+ if (exitError.exitCode === undefined) {
22
+ throw error;
23
+ }
24
+ // Normal exit from shell
25
+ }
26
+ this.logger.divider();
27
+ this.logger.info("Exited container shell.");
28
+ }
29
+ }
30
+ //# sourceMappingURL=ShellCommand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ShellCommand.js","sourceRoot":"","sources":["../../src/commands/ShellCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C;;GAEG;AACH,MAAM,OAAO,YAAa,SAAQ,WAAW;IAC5C,KAAK,CAAC,OAAO;QACZ,gCAAgC;QAChC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACjD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACrB,IAAI,CAAC,aAAa,CACjB,6DAA6D,CAC7D,CAAC;QACH,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;QACpD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAEtB,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAC/B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,+BAA+B;YAC/B,MAAM,SAAS,GAAG,KAA8B,CAAC;YACjD,IAAI,SAAS,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;gBACtC,MAAM,KAAK,CAAC;YACb,CAAC;YACD,yBAAyB;QAC1B,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACtB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;CACD"}
@@ -0,0 +1,19 @@
1
+ import type { StartOptions } from "../config/types.js";
2
+ import { BaseCommand } from "./ICommand.js";
3
+ /**
4
+ * Start ngrok tunnel and Docker container
5
+ */
6
+ export declare class StartCommand extends BaseCommand {
7
+ private options;
8
+ constructor(app: import("../Application.js").Application, options?: StartOptions);
9
+ execute(): Promise<void>;
10
+ /**
11
+ * Print success message with Linear configuration URLs
12
+ */
13
+ private printSuccess;
14
+ /**
15
+ * Build Docker image if needed, using custom tools if configured
16
+ */
17
+ private buildDockerImage;
18
+ }
19
+ //# sourceMappingURL=StartCommand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StartCommand.d.ts","sourceRoot":"","sources":["../../src/commands/StartCommand.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C;;GAEG;AACH,qBAAa,YAAa,SAAQ,WAAW;IAG3C,OAAO,CAAC,OAAO;gBADf,GAAG,EAAE,OAAO,mBAAmB,EAAE,WAAW,EACpC,OAAO,GAAE,YAAiB;IAK7B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAkG9B;;OAEG;IACH,OAAO,CAAC,YAAY;IAmBpB;;OAEG;YACW,gBAAgB;CAoC9B"}
@@ -0,0 +1,147 @@
1
+ import { DEFAULT_PORT } from "../config/constants.js";
2
+ import { ToolConfigService } from "../services/ToolConfigService.js";
3
+ import { BaseCommand } from "./ICommand.js";
4
+ /**
5
+ * Start ngrok tunnel and Docker container
6
+ */
7
+ export class StartCommand extends BaseCommand {
8
+ options;
9
+ constructor(app, options = {}) {
10
+ super(app);
11
+ this.options = options;
12
+ }
13
+ async execute() {
14
+ this.logger.header("Starting Cyrus");
15
+ // Check prerequisites
16
+ await this.requirePrerequisites();
17
+ // Check if already running
18
+ if (this.app.state.isRunning()) {
19
+ const status = await this.app.docker.getStatus();
20
+ if (status.running) {
21
+ this.logger.warn("Cyrus is already running.");
22
+ this.logger.info(`Tunnel URL: ${this.app.state.getTunnelUrl()}`);
23
+ return;
24
+ }
25
+ // State says running but container is not - clean up state
26
+ this.app.state.setStopped();
27
+ }
28
+ // Check for .env.docker
29
+ if (!this.app.docker.hasEnvFile()) {
30
+ this.exitWithError("Configuration not found. Run 'cyrus-docker init' first.");
31
+ }
32
+ // Step 1: Start ngrok tunnel
33
+ this.logger.blank();
34
+ this.logger.info("Step 1: Starting ngrok tunnel...");
35
+ const ngrokProcess = await this.app.tunnel.start(DEFAULT_PORT);
36
+ const ngrokPid = ngrokProcess.pid;
37
+ if (!ngrokPid) {
38
+ this.exitWithError("Failed to get ngrok process PID");
39
+ }
40
+ // Wait for tunnel URL
41
+ let tunnelUrl;
42
+ try {
43
+ tunnelUrl = await this.app.tunnel.waitForUrl();
44
+ }
45
+ catch (error) {
46
+ // Clean up ngrok if we fail to get URL
47
+ await this.app.tunnel.stop(ngrokPid);
48
+ this.exitWithError(`Failed to get tunnel URL: ${error}`);
49
+ }
50
+ // Step 2: Update .env.docker with tunnel URL
51
+ this.logger.blank();
52
+ this.logger.info("Step 2: Updating CYRUS_BASE_URL...");
53
+ this.app.docker.updateEnvValue("CYRUS_BASE_URL", tunnelUrl);
54
+ this.logger.success(`Set CYRUS_BASE_URL=${tunnelUrl}`);
55
+ // Step 3: Build and start Docker container
56
+ this.logger.blank();
57
+ this.logger.info("Step 3: Starting Docker container...");
58
+ try {
59
+ await this.buildDockerImage();
60
+ await this.app.docker.up();
61
+ }
62
+ catch (error) {
63
+ // Clean up ngrok if Docker fails
64
+ await this.app.tunnel.stop(ngrokPid);
65
+ this.exitWithError(`Failed to start container: ${error}`);
66
+ }
67
+ // Step 4: Wait for container to be healthy
68
+ this.logger.blank();
69
+ this.logger.info("Step 4: Waiting for container health check...");
70
+ try {
71
+ await this.app.docker.waitForHealthy();
72
+ }
73
+ catch (error) {
74
+ this.logger.warn(`Health check issue: ${error}`);
75
+ this.logger.info("Container may still be starting up...");
76
+ }
77
+ // Save state
78
+ this.app.state.setRunning(ngrokPid, tunnelUrl, this.app.dockerDir);
79
+ // Print success and Linear configuration URLs
80
+ this.printSuccess(tunnelUrl);
81
+ // Follow logs unless detached
82
+ if (!this.options.detach) {
83
+ this.logger.blank();
84
+ this.logger.info("Following container logs (Ctrl+C to detach)...");
85
+ this.logger.divider();
86
+ try {
87
+ await this.app.docker.logs({ follow: true });
88
+ }
89
+ catch {
90
+ // User pressed Ctrl+C
91
+ this.logger.blank();
92
+ this.logger.info("Detached from logs. Cyrus continues running.");
93
+ this.logger.info("Run 'cyrus-docker logs -f' to follow again.");
94
+ }
95
+ }
96
+ }
97
+ /**
98
+ * Print success message with Linear configuration URLs
99
+ */
100
+ printSuccess(tunnelUrl) {
101
+ this.logger.blank();
102
+ this.logger.header("Cyrus Started Successfully");
103
+ this.logger.blank();
104
+ this.logger.keyValue("Tunnel URL", tunnelUrl);
105
+ this.logger.keyValue("Local Port", String(DEFAULT_PORT));
106
+ this.logger.blank();
107
+ this.logger.info("Configure these URLs in Linear OAuth App:");
108
+ this.logger.raw(` linear.app/settings/api/applications`);
109
+ this.logger.blank();
110
+ this.logger.keyValue("Callback URL", `${tunnelUrl}/callback`, 14);
111
+ this.logger.keyValue("Webhook URL", `${tunnelUrl}/webhook`, 14);
112
+ this.logger.blank();
113
+ this.logger.info("Then run: cyrus-docker auth");
114
+ }
115
+ /**
116
+ * Build Docker image if needed, using custom tools if configured
117
+ */
118
+ async buildDockerImage() {
119
+ const toolConfigService = new ToolConfigService(this.logger);
120
+ const toolConfig = toolConfigService.readConfig();
121
+ const toolsHash = toolConfigService.getConfigHash();
122
+ // Check if rebuild is needed (unless --build flag forces it)
123
+ if (!this.options.build) {
124
+ this.logger.info("Checking if image rebuild is needed...");
125
+ const { needsRebuild, reason } = await this.app.docker.checkImageStatus(toolsHash);
126
+ if (!needsRebuild) {
127
+ this.logger.success(`${reason} - skipping build`);
128
+ return;
129
+ }
130
+ this.logger.info(`${reason} - rebuilding image...`);
131
+ }
132
+ else {
133
+ this.logger.info("Force rebuild requested...");
134
+ }
135
+ // Build with tools if configured
136
+ if (toolConfig) {
137
+ const resolvedConfig = toolConfigService.resolveConfig(toolConfig);
138
+ if (toolConfigService.hasTools(resolvedConfig)) {
139
+ await this.app.docker.buildWithTools(resolvedConfig, toolConfigService.generateDockerfile.bind(toolConfigService), toolsHash);
140
+ return;
141
+ }
142
+ }
143
+ // No tools config or empty config - build normally
144
+ await this.app.docker.build();
145
+ }
146
+ }
147
+ //# sourceMappingURL=StartCommand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StartCommand.js","sourceRoot":"","sources":["../../src/commands/StartCommand.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { BaseCommand } from "./ICommand.js";
2
+ /**
3
+ * Show Cyrus container and tunnel status
4
+ */
5
+ export declare class StatusCommand extends BaseCommand {
6
+ execute(): Promise<void>;
7
+ }
8
+ //# sourceMappingURL=StatusCommand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusCommand.d.ts","sourceRoot":"","sources":["../../src/commands/StatusCommand.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C;;GAEG;AACH,qBAAa,aAAc,SAAQ,WAAW;IACvC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CA4G9B"}
@@ -0,0 +1,89 @@
1
+ import { ToolConfigService } from "../services/ToolConfigService.js";
2
+ import { BaseCommand } from "./ICommand.js";
3
+ /**
4
+ * Show Cyrus container and tunnel status
5
+ */
6
+ export class StatusCommand extends BaseCommand {
7
+ async execute() {
8
+ this.logger.header("Cyrus Docker Status");
9
+ // Get container status
10
+ const containerStatus = await this.app.docker.getStatus();
11
+ // Get tunnel status
12
+ const tunnelStatus = await this.app.tunnel.getStatus();
13
+ // Get image status
14
+ const toolConfigService = new ToolConfigService(this.logger);
15
+ const currentToolsHash = toolConfigService.getConfigHash();
16
+ const imageStatus = await this.app.docker.checkImageStatus(currentToolsHash);
17
+ // Get state info
18
+ const stateInfo = this.app.state.get();
19
+ const startedAt = this.app.state.getStartedAt();
20
+ this.logger.blank();
21
+ // Container status
22
+ if (containerStatus.running) {
23
+ const healthIcon = containerStatus.health === "healthy"
24
+ ? "healthy"
25
+ : containerStatus.health === "starting"
26
+ ? "starting"
27
+ : "unhealthy";
28
+ this.logger.status("Container", containerStatus.health === "healthy", `Running (${healthIcon})`);
29
+ if (containerStatus.uptimeSeconds !== undefined) {
30
+ const uptime = this.app.docker.formatUptime(containerStatus.uptimeSeconds);
31
+ this.logger.keyValue(" Uptime", uptime);
32
+ }
33
+ if (containerStatus.containerId) {
34
+ this.logger.keyValue(" ID", containerStatus.containerId);
35
+ }
36
+ }
37
+ else {
38
+ this.logger.status("Container", false, "Not running");
39
+ }
40
+ this.logger.blank();
41
+ // Tunnel status
42
+ if (tunnelStatus.isRunning && tunnelStatus.url) {
43
+ this.logger.status("Tunnel", true, "Active");
44
+ this.logger.keyValue(" URL", tunnelStatus.url);
45
+ this.logger.keyValue(" Local", `localhost:3456`);
46
+ }
47
+ else {
48
+ this.logger.status("Tunnel", false, "Not running");
49
+ }
50
+ this.logger.blank();
51
+ // Image status
52
+ const imageExists = await this.app.docker.imageExists();
53
+ if (imageExists) {
54
+ this.logger.status("Image", !imageStatus.needsRebuild, imageStatus.reason);
55
+ if (currentToolsHash) {
56
+ this.logger.keyValue(" Tools hash", currentToolsHash);
57
+ }
58
+ }
59
+ else {
60
+ this.logger.status("Image", false, "Not built");
61
+ if (currentToolsHash) {
62
+ this.logger.keyValue(" Tools hash", currentToolsHash);
63
+ }
64
+ }
65
+ // If both are running, show Linear configuration
66
+ if (containerStatus.running && tunnelStatus.isRunning && tunnelStatus.url) {
67
+ this.logger.blank();
68
+ this.logger.divider();
69
+ this.logger.blank();
70
+ this.logger.info("Linear Configuration:");
71
+ this.logger.keyValue(" Callback URL", `${tunnelStatus.url}/callback`, 14);
72
+ this.logger.keyValue(" Webhook URL", `${tunnelStatus.url}/webhook`, 14);
73
+ }
74
+ // Show started time
75
+ if (startedAt && containerStatus.running) {
76
+ this.logger.blank();
77
+ this.logger.divider();
78
+ this.logger.blank();
79
+ this.logger.keyValue("Started", startedAt.toLocaleString(), 10);
80
+ }
81
+ // Show state consistency warning
82
+ if (stateInfo.isRunning && !containerStatus.running) {
83
+ this.logger.blank();
84
+ this.logger.warn("State file says running but container is not. Run 'cyrus-docker stop' to clean up.");
85
+ }
86
+ this.logger.blank();
87
+ }
88
+ }
89
+ //# sourceMappingURL=StatusCommand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusCommand.js","sourceRoot":"","sources":["../../src/commands/StatusCommand.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { BaseCommand } from "./ICommand.js";
2
+ /**
3
+ * Stop Docker container and ngrok tunnel
4
+ */
5
+ export declare class StopCommand extends BaseCommand {
6
+ execute(): Promise<void>;
7
+ }
8
+ //# sourceMappingURL=StopCommand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StopCommand.d.ts","sourceRoot":"","sources":["../../src/commands/StopCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C;;GAEG;AACH,qBAAa,WAAY,SAAQ,WAAW;IACrC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAyC9B"}