@turboops/cli 1.0.0-dev.724 → 1.0.0-dev.725

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 (3) hide show
  1. package/README.md +25 -25
  2. package/dist/index.js +252 -77
  3. package/package.json +16 -16
package/README.md CHANGED
@@ -97,12 +97,12 @@ turbo deploy production --timeout 900000
97
97
 
98
98
  **Options:**
99
99
 
100
- | Option | Description |
101
- |--------|-------------|
102
- | `-i, --image <tag>` | Docker image tag to deploy |
103
- | `-w, --wait` | Wait for deployment to complete (default) |
104
- | `--no-wait` | Do not wait for deployment to complete |
105
- | `--timeout <ms>` | Timeout in milliseconds when waiting (default: 600000) |
100
+ | Option | Description |
101
+ | ------------------- | ------------------------------------------------------ |
102
+ | `-i, --image <tag>` | Docker image tag to deploy |
103
+ | `-w, --wait` | Wait for deployment to complete (default) |
104
+ | `--no-wait` | Do not wait for deployment to complete |
105
+ | `--timeout <ms>` | Timeout in milliseconds when waiting (default: 600000) |
106
106
 
107
107
  **Note:** This command requires a Project Token with `deploy` permission. Set the token via `TURBOOPS_TOKEN` environment variable or `--token` flag.
108
108
 
@@ -135,11 +135,11 @@ turbo pipeline secrets --type github
135
135
 
136
136
  **Options for `pipeline generate`:**
137
137
 
138
- | Option | Description |
139
- |--------|-------------|
140
- | `-t, --type <type>` | Pipeline type: `gitlab` or `github` |
141
- | `-f, --force` | Overwrite existing pipeline file |
142
- | `-o, --output <path>` | Custom output path |
138
+ | Option | Description |
139
+ | --------------------- | ----------------------------------- |
140
+ | `-t, --type <type>` | Pipeline type: `gitlab` or `github` |
141
+ | `-f, --force` | Overwrite existing pipeline file |
142
+ | `-o, --output <path>` | Custom output path |
143
143
 
144
144
  ### Self-Update
145
145
 
@@ -150,10 +150,10 @@ turbo self-update
150
150
 
151
151
  ## Environment Variables
152
152
 
153
- | Variable | Description |
154
- |----------|-------------|
155
- | `TURBOOPS_TOKEN` | API token for authentication |
156
- | `TURBOOPS_PROJECT` | Project slug |
153
+ | Variable | Description |
154
+ | ------------------ | ------------------------------------------ |
155
+ | `TURBOOPS_TOKEN` | API token for authentication |
156
+ | `TURBOOPS_PROJECT` | Project slug |
157
157
  | `TURBOOPS_API_URL` | API URL (default: https://api.turboops.io) |
158
158
 
159
159
  ## Global Options
@@ -169,16 +169,16 @@ turbo self-update
169
169
 
170
170
  ## Exit Codes
171
171
 
172
- | Code | Description |
173
- |------|-------------|
174
- | 0 | Success |
175
- | 1 | General error |
176
- | 2 | Timeout |
177
- | 3 | Network error |
178
- | 10 | Authentication error |
179
- | 11 | Not found |
180
- | 12 | API error |
181
- | 20 | Validation error |
172
+ | Code | Description |
173
+ | ---- | -------------------- |
174
+ | 0 | Success |
175
+ | 1 | General error |
176
+ | 2 | Timeout |
177
+ | 3 | Network error |
178
+ | 10 | Authentication error |
179
+ | 11 | Not found |
180
+ | 12 | API error |
181
+ | 20 | Validation error |
182
182
 
183
183
  ## License
184
184
 
package/dist/index.js CHANGED
@@ -259,7 +259,11 @@ function writeLocalConfig(config) {
259
259
  const projectRoot = findProjectRoot() || process.cwd();
260
260
  const configPath = path.join(projectRoot, LOCAL_CONFIG_FILE);
261
261
  try {
262
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
262
+ fs.writeFileSync(
263
+ configPath,
264
+ JSON.stringify(config, null, 2) + "\n",
265
+ "utf-8"
266
+ );
263
267
  return true;
264
268
  } catch (error) {
265
269
  logger.error(`Failed to write ${LOCAL_CONFIG_FILE}: ${error}`);
@@ -509,7 +513,10 @@ var apiClient = {
509
513
  };
510
514
  }
511
515
  if (process.env.DEBUG) {
512
- console.debug("[API] Response:", JSON.stringify(data, null, 2).substring(0, 500));
516
+ console.debug(
517
+ "[API] Response:",
518
+ JSON.stringify(data, null, 2).substring(0, 500)
519
+ );
513
520
  }
514
521
  return { data, status: response.status };
515
522
  } catch (error) {
@@ -695,31 +702,47 @@ var apiClient = {
695
702
  * Update project's detected configuration (partial update) (CLI endpoint)
696
703
  */
697
704
  async updateProjectConfig(projectId, config) {
698
- return this.request("PATCH", `/cli/deployment/projects/${projectId}/config`, config);
705
+ return this.request(
706
+ "PATCH",
707
+ `/cli/deployment/projects/${projectId}/config`,
708
+ config
709
+ );
699
710
  },
700
711
  /**
701
712
  * Upload compose file content to project (CLI endpoint)
702
713
  */
703
714
  async uploadCompose(projectId, content, message) {
704
- return this.request("POST", `/cli/deployment/projects/${projectId}/compose`, { content, message });
715
+ return this.request(
716
+ "POST",
717
+ `/cli/deployment/projects/${projectId}/compose`,
718
+ { content, message }
719
+ );
705
720
  },
706
721
  /**
707
722
  * Generate CI/CD pipeline configuration (CLI endpoint)
708
723
  */
709
724
  async generatePipeline(projectId, type) {
710
- return this.request("GET", `/cli/deployment/projects/${projectId}/pipeline/${type}`);
725
+ return this.request(
726
+ "GET",
727
+ `/cli/deployment/projects/${projectId}/pipeline/${type}`
728
+ );
711
729
  },
712
730
  /**
713
731
  * Get required secrets for pipeline (CLI endpoint)
714
732
  */
715
733
  async getPipelineSecrets(projectId, type) {
716
- return this.request("GET", `/cli/deployment/projects/${projectId}/pipeline/${type}/secrets`);
734
+ return this.request(
735
+ "GET",
736
+ `/cli/deployment/projects/${projectId}/pipeline/${type}/secrets`
737
+ );
717
738
  },
718
739
  /**
719
740
  * Trigger a deployment (Project Token endpoint for CI/CD)
720
741
  */
721
742
  async deploy(stageId, imageTag, composeFile) {
722
- const body = { stage: stageId };
743
+ const body = {
744
+ stage: stageId
745
+ };
723
746
  if (imageTag) body.imageTag = imageTag;
724
747
  if (composeFile) body.composeFile = composeFile;
725
748
  return this.request("POST", "/project/deployment/deploy", body);
@@ -838,7 +861,10 @@ var authService = {
838
861
  logger.info("Initialisiere Anmeldung...");
839
862
  const authInit = await this.initAuth();
840
863
  if (!authInit) {
841
- return { error: "Konnte Authentifizierung nicht initialisieren", success: false };
864
+ return {
865
+ error: "Konnte Authentifizierung nicht initialisieren",
866
+ success: false
867
+ };
842
868
  }
843
869
  logger.newline();
844
870
  logger.info("Bitte autorisieren Sie die CLI in Ihrem Browser.");
@@ -869,7 +895,10 @@ var authService = {
869
895
  };
870
896
  }
871
897
  if (result.status === "expired" || result.status === "consumed") {
872
- return { error: "Autorisierungscode abgelaufen oder bereits verwendet", success: false };
898
+ return {
899
+ error: "Autorisierungscode abgelaufen oder bereits verwendet",
900
+ success: false
901
+ };
873
902
  }
874
903
  await new Promise((resolve4) => setTimeout(resolve4, pollInterval));
875
904
  }
@@ -917,13 +946,16 @@ var loginCommand = new Command("login").description("Authenticate with TurboOps
917
946
  if (options.token) {
918
947
  configService.setToken(options.token);
919
948
  if (options.token.startsWith("turbo_cli_")) {
920
- const { data: data2, error: error2 } = await withSpinner("Verifying token...", async () => {
921
- const result2 = await authService.validateToken(options.token);
922
- if (result2.valid && result2.user) {
923
- return { data: result2.user, error: void 0 };
949
+ const { data: data2, error: error2 } = await withSpinner(
950
+ "Verifying token...",
951
+ async () => {
952
+ const result2 = await authService.validateToken(options.token);
953
+ if (result2.valid && result2.user) {
954
+ return { data: result2.user, error: void 0 };
955
+ }
956
+ return { data: void 0, error: "Invalid token" };
924
957
  }
925
- return { data: void 0, error: "Invalid token" };
926
- });
958
+ );
927
959
  if (error2 || !data2) {
928
960
  configService.clearToken();
929
961
  logger.error(`Authentication failed: ${error2 || "Invalid token"}`);
@@ -957,18 +989,27 @@ var loginCommand = new Command("login").description("Authenticate with TurboOps
957
989
  const result = await authService.browserLogin();
958
990
  if (!result.success) {
959
991
  logger.error(`Login failed: ${result.error || "Unknown error"}`);
960
- addJsonData({ authenticated: false, error: result.error || "Unknown error" });
992
+ addJsonData({
993
+ authenticated: false,
994
+ error: result.error || "Unknown error"
995
+ });
961
996
  process.exit(10 /* AUTH_ERROR */);
962
997
  }
963
998
  addJsonData({
964
999
  authenticated: true,
965
- user: result.user ? { email: result.user.email, fullName: result.user.fullName, id: result.user.id } : void 0
1000
+ user: result.user ? {
1001
+ email: result.user.email,
1002
+ fullName: result.user.fullName,
1003
+ id: result.user.id
1004
+ } : void 0
966
1005
  });
967
1006
  logger.newline();
968
1007
  logger.success(`Angemeldet als ${result.user?.email || "Unknown"}`);
969
1008
  logger.newline();
970
1009
  logger.info("Ihre Anmeldedaten wurden gespeichert.");
971
- logger.info("F\xFChren Sie `turbo whoami` aus, um Ihre Authentifizierung zu \xFCberpr\xFCfen.");
1010
+ logger.info(
1011
+ "F\xFChren Sie `turbo whoami` aus, um Ihre Authentifizierung zu \xFCberpr\xFCfen."
1012
+ );
972
1013
  });
973
1014
  var logoutCommand = new Command("logout").description("Remove stored authentication").action(() => {
974
1015
  configService.clearToken();
@@ -983,13 +1024,16 @@ var whoamiCommand = new Command("whoami").description("Show current authenticate
983
1024
  }
984
1025
  const token = configService.getToken();
985
1026
  if (token?.startsWith("turbo_cli_")) {
986
- const { data: data2, error: error2 } = await withSpinner("Fetching user info...", async () => {
987
- const result = await authService.validateToken(token);
988
- if (result.valid && result.user) {
989
- return { data: result.user, error: void 0 };
1027
+ const { data: data2, error: error2 } = await withSpinner(
1028
+ "Fetching user info...",
1029
+ async () => {
1030
+ const result = await authService.validateToken(token);
1031
+ if (result.valid && result.user) {
1032
+ return { data: result.user, error: void 0 };
1033
+ }
1034
+ return { data: void 0, error: "Invalid token" };
990
1035
  }
991
- return { data: void 0, error: "Invalid token" };
992
- });
1036
+ );
993
1037
  if (error2 || !data2) {
994
1038
  logger.error(`Failed to fetch user info: ${error2 || "Unknown error"}`);
995
1039
  addJsonData({ authenticated: false, error: error2 || "Unknown error" });
@@ -1058,7 +1102,9 @@ async function requireAuth() {
1058
1102
  if (token?.startsWith("turbo_cli_")) {
1059
1103
  const validation = await authService.checkCliToken();
1060
1104
  if (!validation.valid) {
1061
- logger.error("Session expired or revoked. Please run `turbo login` to re-authenticate.");
1105
+ logger.error(
1106
+ "Session expired or revoked. Please run `turbo login` to re-authenticate."
1107
+ );
1062
1108
  configService.clearToken();
1063
1109
  process.exit(10 /* AUTH_ERROR */);
1064
1110
  }
@@ -1179,7 +1225,9 @@ var statusCommand = new Command2("status").description("Show deployment status")
1179
1225
  });
1180
1226
  }
1181
1227
  });
1182
- var configCommand = new Command2("config").description("Manage configuration");
1228
+ var configCommand = new Command2("config").description(
1229
+ "Manage configuration"
1230
+ );
1183
1231
  configCommand.command("show", { isDefault: true }).description("Show current configuration").action(() => {
1184
1232
  const config = configService.getAll();
1185
1233
  addJsonData({ config });
@@ -1281,7 +1329,13 @@ var AI_TOOLS = {
1281
1329
  claude: {
1282
1330
  name: "Claude Code",
1283
1331
  command: "claude",
1284
- args: ["-p", "--dangerously-skip-permissions", "--verbose", "--output-format", "stream-json"]
1332
+ args: [
1333
+ "-p",
1334
+ "--dangerously-skip-permissions",
1335
+ "--verbose",
1336
+ "--output-format",
1337
+ "stream-json"
1338
+ ]
1285
1339
  },
1286
1340
  codex: {
1287
1341
  name: "OpenAI Codex",
@@ -1312,7 +1366,9 @@ var aiToolsService = {
1312
1366
  async selectTool() {
1313
1367
  const available = this.getAvailableTools();
1314
1368
  if (available.length === 0) {
1315
- logger.error("Kein AI-Tool gefunden. Bitte installieren Sie Claude Code oder OpenAI Codex.");
1369
+ logger.error(
1370
+ "Kein AI-Tool gefunden. Bitte installieren Sie Claude Code oder OpenAI Codex."
1371
+ );
1316
1372
  logger.newline();
1317
1373
  logger.info(" Claude Code: https://claude.ai/code");
1318
1374
  logger.info(" OpenAI Codex: https://openai.com/codex");
@@ -1345,9 +1401,15 @@ var aiToolsService = {
1345
1401
  console.log(chalk4.cyan("[DEBUG] === AI Tool Debug Mode ==="));
1346
1402
  console.log(chalk4.dim(`[DEBUG] Tool: ${config.name}`));
1347
1403
  console.log(chalk4.dim(`[DEBUG] Command: ${config.command}`));
1348
- console.log(chalk4.dim(`[DEBUG] Args: ${config.args.join(" ")} + prompt (${prompt.length} chars)`));
1404
+ console.log(
1405
+ chalk4.dim(
1406
+ `[DEBUG] Args: ${config.args.join(" ")} + prompt (${prompt.length} chars)`
1407
+ )
1408
+ );
1349
1409
  console.log(chalk4.dim(`[DEBUG] CWD: ${process.cwd()}`));
1350
- console.log(chalk4.dim(`[DEBUG] Prompt preview: ${prompt.substring(0, 100)}...`));
1410
+ console.log(
1411
+ chalk4.dim(`[DEBUG] Prompt preview: ${prompt.substring(0, 100)}...`)
1412
+ );
1351
1413
  console.log("");
1352
1414
  }
1353
1415
  const spinner = ora2({
@@ -1373,7 +1435,9 @@ var aiToolsService = {
1373
1435
  child.stdin?.end();
1374
1436
  if (verbose) {
1375
1437
  spinner.stop();
1376
- console.log(chalk4.dim(`[DEBUG] Child process spawned, PID: ${child.pid}`));
1438
+ console.log(
1439
+ chalk4.dim(`[DEBUG] Child process spawned, PID: ${child.pid}`)
1440
+ );
1377
1441
  console.log(chalk4.dim(`[DEBUG] Waiting for output...`));
1378
1442
  spinner.start();
1379
1443
  }
@@ -1408,7 +1472,11 @@ var aiToolsService = {
1408
1472
  spinner.text = action;
1409
1473
  if (verbose) {
1410
1474
  spinner.stop();
1411
- console.log(chalk4.dim(`[TOOL] ${block.name}: ${JSON.stringify(block.input).substring(0, 200)}`));
1475
+ console.log(
1476
+ chalk4.dim(
1477
+ `[TOOL] ${block.name}: ${JSON.stringify(block.input).substring(0, 200)}`
1478
+ )
1479
+ );
1412
1480
  spinner.start();
1413
1481
  }
1414
1482
  }
@@ -1447,9 +1515,13 @@ var aiToolsService = {
1447
1515
  if (verbose) {
1448
1516
  spinner.stop();
1449
1517
  console.log(chalk4.dim(`[DEBUG] Process exited with code: ${code}`));
1450
- console.log(chalk4.dim(`[DEBUG] Total output length: ${rawOutput.length} chars`));
1518
+ console.log(
1519
+ chalk4.dim(`[DEBUG] Total output length: ${rawOutput.length} chars`)
1520
+ );
1451
1521
  if (rawOutput.length === 0) {
1452
- console.log(chalk4.yellow(`[DEBUG] No output received from ${config.name}!`));
1522
+ console.log(
1523
+ chalk4.yellow(`[DEBUG] No output received from ${config.name}!`)
1524
+ );
1453
1525
  }
1454
1526
  }
1455
1527
  if (code === 0) {
@@ -1471,7 +1543,9 @@ var aiToolsService = {
1471
1543
  if (verbose) {
1472
1544
  console.log(chalk4.red(`[ERROR] Spawn error: ${err.message}`));
1473
1545
  }
1474
- spinner.fail(`Fehler beim Ausf\xFChren von ${config.name}: ${err.message}`);
1546
+ spinner.fail(
1547
+ `Fehler beim Ausf\xFChren von ${config.name}: ${err.message}`
1548
+ );
1475
1549
  resolve4(false);
1476
1550
  });
1477
1551
  });
@@ -1512,7 +1586,12 @@ async function detectProjectConfig() {
1512
1586
  hasGitHubPipeline: false,
1513
1587
  hasTurboOpsInPipeline: false
1514
1588
  };
1515
- const composePaths = ["docker-compose.yml", "docker-compose.yaml", "compose.yml", "compose.yaml"];
1589
+ const composePaths = [
1590
+ "docker-compose.yml",
1591
+ "docker-compose.yaml",
1592
+ "compose.yml",
1593
+ "compose.yaml"
1594
+ ];
1516
1595
  for (const composePath of composePaths) {
1517
1596
  try {
1518
1597
  await fs2.access(path2.join(cwd, composePath));
@@ -1533,7 +1612,9 @@ async function detectProjectConfig() {
1533
1612
  const githubPath = path2.join(cwd, ".github", "workflows");
1534
1613
  try {
1535
1614
  const files = await fs2.readdir(githubPath);
1536
- const ymlFiles = files.filter((f) => f.endsWith(".yml") || f.endsWith(".yaml"));
1615
+ const ymlFiles = files.filter(
1616
+ (f) => f.endsWith(".yml") || f.endsWith(".yaml")
1617
+ );
1537
1618
  if (ymlFiles.length > 0) {
1538
1619
  result.hasGitHubPipeline = true;
1539
1620
  result.pipelinePath = `.github/workflows/${ymlFiles[0]}`;
@@ -1573,7 +1654,9 @@ var initCommand = new Command3("init").description("Initialize TurboOps project
1573
1654
  }
1574
1655
  const result = await authService.browserLogin();
1575
1656
  if (!result.success) {
1576
- logger.error(`Anmeldung fehlgeschlagen: ${result.error || "Unbekannter Fehler"}`);
1657
+ logger.error(
1658
+ `Anmeldung fehlgeschlagen: ${result.error || "Unbekannter Fehler"}`
1659
+ );
1577
1660
  addJsonData({
1578
1661
  error: result.error || "Unknown error",
1579
1662
  initialized: false,
@@ -1601,7 +1684,9 @@ var initCommand = new Command3("init").description("Initialize TurboOps project
1601
1684
  }
1602
1685
  const result = await authService.browserLogin();
1603
1686
  if (!result.success) {
1604
- logger.error(`Anmeldung fehlgeschlagen: ${result.error || "Unbekannter Fehler"}`);
1687
+ logger.error(
1688
+ `Anmeldung fehlgeschlagen: ${result.error || "Unbekannter Fehler"}`
1689
+ );
1605
1690
  addJsonData({
1606
1691
  error: result.error || "Unknown error",
1607
1692
  initialized: false,
@@ -1740,13 +1825,23 @@ async function createNewProject(slug, verbose = false) {
1740
1825
  if (newProject.projectToken) {
1741
1826
  logger.newline();
1742
1827
  logger.header("CI/CD Projekt-Token");
1743
- console.log(chalk5.yellow.bold(" WICHTIG: Diesen Token jetzt kopieren - er wird nur einmal angezeigt!"));
1828
+ console.log(
1829
+ chalk5.yellow.bold(
1830
+ " WICHTIG: Diesen Token jetzt kopieren - er wird nur einmal angezeigt!"
1831
+ )
1832
+ );
1744
1833
  logger.newline();
1745
- console.log(chalk5.cyan(" Token: ") + chalk5.green.bold(newProject.projectToken));
1834
+ console.log(
1835
+ chalk5.cyan(" Token: ") + chalk5.green.bold(newProject.projectToken)
1836
+ );
1746
1837
  logger.newline();
1747
1838
  console.log(chalk5.dim(" Diesen Token als CI/CD Secret hinterlegen:"));
1748
- console.log(chalk5.dim(" \u2192 GitLab: Settings \u2192 CI/CD \u2192 Variables \u2192 TURBOOPS_TOKEN"));
1749
- console.log(chalk5.dim(" \u2192 GitHub: Settings \u2192 Secrets \u2192 Actions \u2192 TURBOOPS_TOKEN"));
1839
+ console.log(
1840
+ chalk5.dim(" \u2192 GitLab: Settings \u2192 CI/CD \u2192 Variables \u2192 TURBOOPS_TOKEN")
1841
+ );
1842
+ console.log(
1843
+ chalk5.dim(" \u2192 GitHub: Settings \u2192 Secrets \u2192 Actions \u2192 TURBOOPS_TOKEN")
1844
+ );
1750
1845
  logger.newline();
1751
1846
  }
1752
1847
  configService.setProject(newProject.slug);
@@ -1850,7 +1945,9 @@ async function createPipeline(projectId) {
1850
1945
  () => apiClient.generatePipeline(projectId, pipelineDetails.pipelineType)
1851
1946
  );
1852
1947
  if (error || !pipeline) {
1853
- logger.error(`Pipeline konnte nicht generiert werden: ${error || "Unbekannter Fehler"}`);
1948
+ logger.error(
1949
+ `Pipeline konnte nicht generiert werden: ${error || "Unbekannter Fehler"}`
1950
+ );
1854
1951
  return;
1855
1952
  }
1856
1953
  const fs4 = await import("fs/promises");
@@ -1873,7 +1970,10 @@ async function createPipeline(projectId) {
1873
1970
  }
1874
1971
  });
1875
1972
  logger.newline();
1876
- const { data: secrets } = await apiClient.getPipelineSecrets(projectId, pipelineDetails.pipelineType);
1973
+ const { data: secrets } = await apiClient.getPipelineSecrets(
1974
+ projectId,
1975
+ pipelineDetails.pipelineType
1976
+ );
1877
1977
  if (secrets && secrets.length > 0) {
1878
1978
  logger.header("Erforderliche CI/CD Secrets");
1879
1979
  for (const secret of secrets) {
@@ -1940,12 +2040,18 @@ async function showFinalSummary(project) {
1940
2040
  console.log(chalk5.cyan(" 2. Token als CI/CD Secret hinterlegen:"));
1941
2041
  console.log(chalk5.dim(" GitLab:"));
1942
2042
  console.log(` ${chalk5.dim("\u2192")} Settings \u2192 CI/CD \u2192 Variables`);
1943
- console.log(` ${chalk5.dim("\u2192")} Variable: ${chalk5.bold("TURBOOPS_TOKEN")} = <dein-token>`);
2043
+ console.log(
2044
+ ` ${chalk5.dim("\u2192")} Variable: ${chalk5.bold("TURBOOPS_TOKEN")} = <dein-token>`
2045
+ );
1944
2046
  console.log(` ${chalk5.dim("\u2192")} Flags: Protected, Masked`);
1945
2047
  logger.newline();
1946
2048
  console.log(chalk5.dim(" GitHub:"));
1947
- console.log(` ${chalk5.dim("\u2192")} Settings \u2192 Secrets and variables \u2192 Actions`);
1948
- console.log(` ${chalk5.dim("\u2192")} New repository secret: ${chalk5.bold("TURBOOPS_TOKEN")}`);
2049
+ console.log(
2050
+ ` ${chalk5.dim("\u2192")} Settings \u2192 Secrets and variables \u2192 Actions`
2051
+ );
2052
+ console.log(
2053
+ ` ${chalk5.dim("\u2192")} New repository secret: ${chalk5.bold("TURBOOPS_TOKEN")}`
2054
+ );
1949
2055
  logger.newline();
1950
2056
  logger.header("N\xE4chste Schritte");
1951
2057
  logger.list([
@@ -1977,7 +2083,10 @@ async function offerAiAssistance(projectSlug, projectId, verbose = false) {
1977
2083
  message: "Docker-Setup:",
1978
2084
  choices: [
1979
2085
  { title: "Bestehende docker-compose.yml verwenden", value: "keep" },
1980
- { title: "Neu erstellen mit AI (\xFCberschreibt bestehende)", value: "create" }
2086
+ {
2087
+ title: "Neu erstellen mit AI (\xFCberschreibt bestehende)",
2088
+ value: "create"
2089
+ }
1981
2090
  ],
1982
2091
  initial: 0
1983
2092
  });
@@ -1986,7 +2095,9 @@ async function offerAiAssistance(projectSlug, projectId, verbose = false) {
1986
2095
  }
1987
2096
  } else {
1988
2097
  logger.warning("Keine docker-compose.yml gefunden.");
1989
- logger.info("TurboOps Deployment ben\xF6tigt eine docker-compose.yml auf Root-Ebene.");
2098
+ logger.info(
2099
+ "TurboOps Deployment ben\xF6tigt eine docker-compose.yml auf Root-Ebene."
2100
+ );
1990
2101
  const { shouldCreateDocker } = await prompts2({
1991
2102
  type: "confirm",
1992
2103
  name: "shouldCreateDocker",
@@ -2019,12 +2130,20 @@ async function offerAiAssistance(projectSlug, projectId, verbose = false) {
2019
2130
  message: "Pipeline-Setup:",
2020
2131
  choices: [
2021
2132
  { title: "Bestehende Pipeline behalten", value: "keep" },
2022
- { title: "Mit AI neu integrieren (\xFCberschreibt TurboOps-Teil)", value: "integrate" }
2133
+ {
2134
+ title: "Mit AI neu integrieren (\xFCberschreibt TurboOps-Teil)",
2135
+ value: "integrate"
2136
+ }
2023
2137
  ],
2024
2138
  initial: 0
2025
2139
  });
2026
2140
  if (pipelineAction === "integrate") {
2027
- await integratePipelineWithAI(detection, projectSlug, verbose, projectId);
2141
+ await integratePipelineWithAI(
2142
+ detection,
2143
+ projectSlug,
2144
+ verbose,
2145
+ projectId
2146
+ );
2028
2147
  }
2029
2148
  } else {
2030
2149
  logger.info(`${pipelineType} Pipeline gefunden (ohne TurboOps).`);
@@ -2035,7 +2154,12 @@ async function offerAiAssistance(projectSlug, projectId, verbose = false) {
2035
2154
  initial: true
2036
2155
  });
2037
2156
  if (shouldIntegrate) {
2038
- await integratePipelineWithAI(detection, projectSlug, verbose, projectId);
2157
+ await integratePipelineWithAI(
2158
+ detection,
2159
+ projectSlug,
2160
+ verbose,
2161
+ projectId
2162
+ );
2039
2163
  }
2040
2164
  }
2041
2165
  } else {
@@ -2221,7 +2345,11 @@ async function detectAndUploadCompose(projectSlug) {
2221
2345
  }
2222
2346
  try {
2223
2347
  const content = readFileSync2(fullPath, "utf-8");
2224
- const { error } = await apiClient.uploadCompose(project.id, content, "Uploaded via turbo init");
2348
+ const { error } = await apiClient.uploadCompose(
2349
+ project.id,
2350
+ content,
2351
+ "Uploaded via turbo init"
2352
+ );
2225
2353
  if (error) {
2226
2354
  logger.warning(`Compose-Upload fehlgeschlagen: ${error}`);
2227
2355
  } else {
@@ -2243,7 +2371,9 @@ async function integratePipelineWithAI(detection, projectSlug, verbose = false,
2243
2371
  () => apiClient.generatePipeline(projectId, pipelineType)
2244
2372
  );
2245
2373
  if (error || !pipelineTemplate) {
2246
- logger.warning(`Pipeline-Template konnte nicht geladen werden: ${error || "Unbekannter Fehler"}`);
2374
+ logger.warning(
2375
+ `Pipeline-Template konnte nicht geladen werden: ${error || "Unbekannter Fehler"}`
2376
+ );
2247
2377
  logger.info("Claude Code wird ein generisches Template verwenden.");
2248
2378
  } else {
2249
2379
  templateContent = pipelineTemplate.content;
@@ -2362,7 +2492,9 @@ Erstelle die Datei "${pipelineFile}".`;
2362
2492
  });
2363
2493
  }
2364
2494
  logger.newline();
2365
- logger.info("Vergessen Sie nicht, das CI/CD Secret TURBOOPS_TOKEN zu konfigurieren.");
2495
+ logger.info(
2496
+ "Vergessen Sie nicht, das CI/CD Secret TURBOOPS_TOKEN zu konfigurieren."
2497
+ );
2366
2498
  }
2367
2499
  }
2368
2500
 
@@ -2401,11 +2533,13 @@ function detectCiEnvironment() {
2401
2533
  if (process.env.JENKINS_URL) return "Jenkins";
2402
2534
  return null;
2403
2535
  }
2404
- var deployCommand = new Command4("deploy").description("Trigger a deployment (for CI/CD pipelines)").argument("<environment>", "Environment slug (e.g., production, staging)").option("-i, --image <tag>", "Docker image tag to deploy (auto-detected in CI/CD)").option("-c, --compose <path>", "Path to docker-compose file (auto-detected by default)").option("-w, --wait", "Wait for deployment to complete", true).option("--no-wait", "Do not wait for deployment to complete").option(
2405
- "--timeout <ms>",
2406
- "Timeout in milliseconds when waiting",
2407
- "600000"
2408
- ).action(async (environment, options) => {
2536
+ var deployCommand = new Command4("deploy").description("Trigger a deployment (for CI/CD pipelines)").argument("<environment>", "Environment slug (e.g., production, staging)").option(
2537
+ "-i, --image <tag>",
2538
+ "Docker image tag to deploy (auto-detected in CI/CD)"
2539
+ ).option(
2540
+ "-c, --compose <path>",
2541
+ "Path to docker-compose file (auto-detected by default)"
2542
+ ).option("-w, --wait", "Wait for deployment to complete", true).option("--no-wait", "Do not wait for deployment to complete").option("--timeout <ms>", "Timeout in milliseconds when waiting", "600000").action(async (environment, options) => {
2409
2543
  const { project, environment: env } = await getCommandContextWithEnvironment(environment);
2410
2544
  logger.header(`Deploying: ${project.name} \u2192 ${env.name}`);
2411
2545
  let imageTag = options.image;
@@ -2428,10 +2562,15 @@ var deployCommand = new Command4("deploy").description("Trigger a deployment (fo
2428
2562
  composeFileContent = readFileSync3(composePath, "utf-8");
2429
2563
  logger.info(`Using compose file: ${composePath}`);
2430
2564
  } else if (project.detectedConfig?.composePath) {
2431
- const composePath = resolve2(process.cwd(), project.detectedConfig.composePath);
2565
+ const composePath = resolve2(
2566
+ process.cwd(),
2567
+ project.detectedConfig.composePath
2568
+ );
2432
2569
  if (existsSync4(composePath)) {
2433
2570
  composeFileContent = readFileSync3(composePath, "utf-8");
2434
- logger.info(`Using project compose file: ${project.detectedConfig.composePath}`);
2571
+ logger.info(
2572
+ `Using project compose file: ${project.detectedConfig.composePath}`
2573
+ );
2435
2574
  }
2436
2575
  }
2437
2576
  logger.info("Triggering deployment...");
@@ -2537,7 +2676,9 @@ import prompts3 from "prompts";
2537
2676
  import chalk7 from "chalk";
2538
2677
  import * as fs3 from "fs/promises";
2539
2678
  import * as path3 from "path";
2540
- var pipelineCommand = new Command5("pipeline").description("Manage CI/CD pipeline configuration");
2679
+ var pipelineCommand = new Command5("pipeline").description(
2680
+ "Manage CI/CD pipeline configuration"
2681
+ );
2541
2682
  pipelineCommand.command("generate").description("Generate CI/CD pipeline configuration").option("-t, --type <type>", "Pipeline type (gitlab, github)").option("-f, --force", "Overwrite existing pipeline file").option("-o, --output <path>", "Custom output path").action(async (options) => {
2542
2683
  const { project } = await getCommandContext();
2543
2684
  logger.header("CI/CD Pipeline generieren");
@@ -2577,14 +2718,21 @@ pipelineCommand.command("generate").description("Generate CI/CD pipeline configu
2577
2718
  pipelineType = selectedType;
2578
2719
  }
2579
2720
  if (!["gitlab", "github"].includes(pipelineType)) {
2580
- logger.error(`Ung\xFCltiger Pipeline-Typ: ${pipelineType}. Erlaubt: gitlab, github`);
2721
+ logger.error(
2722
+ `Ung\xFCltiger Pipeline-Typ: ${pipelineType}. Erlaubt: gitlab, github`
2723
+ );
2581
2724
  process.exit(14 /* VALIDATION_ERROR */);
2582
2725
  }
2583
2726
  let outputPath;
2584
2727
  if (options.output) {
2585
2728
  outputPath = path3.resolve(options.output);
2586
2729
  } else if (pipelineType === "github") {
2587
- outputPath = path3.join(process.cwd(), ".github", "workflows", "deploy.yml");
2730
+ outputPath = path3.join(
2731
+ process.cwd(),
2732
+ ".github",
2733
+ "workflows",
2734
+ "deploy.yml"
2735
+ );
2588
2736
  } else {
2589
2737
  outputPath = path3.join(process.cwd(), ".gitlab-ci.yml");
2590
2738
  }
@@ -2599,7 +2747,10 @@ pipelineCommand.command("generate").description("Generate CI/CD pipeline configu
2599
2747
  name: "action",
2600
2748
  message: `${path3.basename(outputPath)} existiert bereits ohne TurboOps.`,
2601
2749
  choices: [
2602
- { title: "Mit AI integrieren (empfohlen)", value: "ai-integrate" },
2750
+ {
2751
+ title: "Mit AI integrieren (empfohlen)",
2752
+ value: "ai-integrate"
2753
+ },
2603
2754
  { title: "\xDCberschreiben", value: "overwrite" },
2604
2755
  { title: "Abbrechen", value: "cancel" }
2605
2756
  ]
@@ -2610,7 +2761,11 @@ pipelineCommand.command("generate").description("Generate CI/CD pipeline configu
2610
2761
  return;
2611
2762
  }
2612
2763
  if (action === "ai-integrate") {
2613
- await integratePipelineWithAI2(pipelineType, project.slug, outputPath);
2764
+ await integratePipelineWithAI2(
2765
+ pipelineType,
2766
+ project.slug,
2767
+ outputPath
2768
+ );
2614
2769
  return;
2615
2770
  }
2616
2771
  } else {
@@ -2634,7 +2789,9 @@ pipelineCommand.command("generate").description("Generate CI/CD pipeline configu
2634
2789
  () => apiClient.generatePipeline(project.id, pipelineType)
2635
2790
  );
2636
2791
  if (error || !pipeline) {
2637
- logger.error(`Pipeline konnte nicht generiert werden: ${error || "Unbekannter Fehler"}`);
2792
+ logger.error(
2793
+ `Pipeline konnte nicht generiert werden: ${error || "Unbekannter Fehler"}`
2794
+ );
2638
2795
  addJsonData({ error: error || "Unknown error", generated: false });
2639
2796
  process.exit(13 /* API_ERROR */);
2640
2797
  }
@@ -2642,7 +2799,9 @@ pipelineCommand.command("generate").description("Generate CI/CD pipeline configu
2642
2799
  await fs3.mkdir(outputDir, { recursive: true });
2643
2800
  try {
2644
2801
  await fs3.writeFile(outputPath, pipeline.content, "utf-8");
2645
- logger.success(`${path3.relative(process.cwd(), outputPath)} wurde erstellt!`);
2802
+ logger.success(
2803
+ `${path3.relative(process.cwd(), outputPath)} wurde erstellt!`
2804
+ );
2646
2805
  addJsonData({
2647
2806
  filename: path3.relative(process.cwd(), outputPath),
2648
2807
  generated: true,
@@ -2662,14 +2821,21 @@ pipelineCommand.command("secrets").description("Show required CI/CD secrets").op
2662
2821
  const { project } = await getCommandContext();
2663
2822
  const pipelineType = options.type;
2664
2823
  if (!["gitlab", "github"].includes(pipelineType)) {
2665
- logger.error(`Ung\xFCltiger Pipeline-Typ: ${pipelineType}. Erlaubt: gitlab, github`);
2824
+ logger.error(
2825
+ `Ung\xFCltiger Pipeline-Typ: ${pipelineType}. Erlaubt: gitlab, github`
2826
+ );
2666
2827
  process.exit(14 /* VALIDATION_ERROR */);
2667
2828
  }
2668
- logger.header(`CI/CD Secrets f\xFCr ${pipelineType === "gitlab" ? "GitLab" : "GitHub"}`);
2829
+ logger.header(
2830
+ `CI/CD Secrets f\xFCr ${pipelineType === "gitlab" ? "GitLab" : "GitHub"}`
2831
+ );
2669
2832
  await showSecrets(project.id, pipelineType);
2670
2833
  });
2671
2834
  async function showSecrets(projectId, pipelineType) {
2672
- const { data: secrets, error } = await apiClient.getPipelineSecrets(projectId, pipelineType);
2835
+ const { data: secrets, error } = await apiClient.getPipelineSecrets(
2836
+ projectId,
2837
+ pipelineType
2838
+ );
2673
2839
  if (error) {
2674
2840
  logger.error(`Fehler beim Laden der Secrets: ${error}`);
2675
2841
  return;
@@ -2889,7 +3055,9 @@ Modifiziere die Datei "${pipelinePath}" entsprechend.`;
2889
3055
  if (success) {
2890
3056
  logger.success("Pipeline wurde mit AI aktualisiert!");
2891
3057
  logger.newline();
2892
- logger.info("Vergessen Sie nicht, das CI/CD Secret TURBOOPS_TOKEN zu konfigurieren.");
3058
+ logger.info(
3059
+ "Vergessen Sie nicht, das CI/CD Secret TURBOOPS_TOKEN zu konfigurieren."
3060
+ );
2893
3061
  addJsonData({ generated: true, method: "ai-integration" });
2894
3062
  } else {
2895
3063
  addJsonData({ generated: false, reason: "ai_failed" });
@@ -3035,7 +3203,9 @@ WICHTIG - TURBOOPS DEPLOYMENT:
3035
3203
  - Verhindert Port-Konflikte bei mehreren Projekten auf einem Server
3036
3204
 
3037
3205
  Erstelle alle notwendigen Dateien.`;
3038
- var dockerCommand = new Command6("docker").description("Manage Docker configuration");
3206
+ var dockerCommand = new Command6("docker").description(
3207
+ "Manage Docker configuration"
3208
+ );
3039
3209
  dockerCommand.command("generate").description("Docker-Setup (docker-compose + Dockerfiles) mit AI erstellen").option("-f, --force", "Bestehende Dateien \xFCberschreiben").action(async (options) => {
3040
3210
  logger.header("Docker-Setup generieren");
3041
3211
  const detection = await detectProjectConfig();
@@ -3058,7 +3228,10 @@ dockerCommand.command("generate").description("Docker-Setup (docker-compose + Do
3058
3228
  addJsonData({ generated: false, reason: "no_ai_tool" });
3059
3229
  return;
3060
3230
  }
3061
- const success = await aiToolsService.runWithPrompt(tool, DOCKER_SETUP_PROMPT);
3231
+ const success = await aiToolsService.runWithPrompt(
3232
+ tool,
3233
+ DOCKER_SETUP_PROMPT
3234
+ );
3062
3235
  if (success) {
3063
3236
  logger.success("Docker-Setup wurde erstellt!");
3064
3237
  logger.newline();
@@ -3070,7 +3243,9 @@ dockerCommand.command("generate").description("Docker-Setup (docker-compose + Do
3070
3243
  ]);
3071
3244
  addJsonData({ generated: true });
3072
3245
  } else {
3073
- logger.warning("Docker-Setup Generierung wurde abgebrochen oder ist fehlgeschlagen.");
3246
+ logger.warning(
3247
+ "Docker-Setup Generierung wurde abgebrochen oder ist fehlgeschlagen."
3248
+ );
3074
3249
  addJsonData({ generated: false, reason: "ai_failed" });
3075
3250
  }
3076
3251
  });
package/package.json CHANGED
@@ -1,17 +1,29 @@
1
1
  {
2
2
  "name": "@turboops/cli",
3
- "version": "1.0.0-dev.724",
3
+ "version": "1.0.0-dev.725",
4
4
  "description": "TurboCLI - Command line interface for TurboOps deployments",
5
- "author": "lenne.tech GmbH",
5
+ "keywords": [
6
+ "cli",
7
+ "deployment",
8
+ "docker",
9
+ "swarm",
10
+ "turboops"
11
+ ],
6
12
  "license": "MIT",
7
- "type": "module",
8
- "main": "./dist/index.js",
13
+ "author": "lenne.tech GmbH",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/lenne-tech/turboops.git",
17
+ "directory": "projects/cli"
18
+ },
9
19
  "bin": {
10
20
  "turbo": "./dist/index.js"
11
21
  },
12
22
  "files": [
13
23
  "dist"
14
24
  ],
25
+ "type": "module",
26
+ "main": "./dist/index.js",
15
27
  "dependencies": {
16
28
  "chalk": "^5.3.0",
17
29
  "commander": "^12.1.0",
@@ -32,18 +44,6 @@
32
44
  "engines": {
33
45
  "node": ">=18.0.0"
34
46
  },
35
- "keywords": [
36
- "turboops",
37
- "cli",
38
- "deployment",
39
- "docker",
40
- "swarm"
41
- ],
42
- "repository": {
43
- "type": "git",
44
- "url": "https://github.com/lenne-tech/turboops.git",
45
- "directory": "projects/cli"
46
- },
47
47
  "scripts": {
48
48
  "build": "tsup src/index.ts --format esm --dts --clean",
49
49
  "build:local": "tsup src/index.ts --format esm --dts --clean --define.__TURBOOPS_ENV__=\"'local'\"",