onflyt-cli 1.0.1-beta.2 → 1.0.1-beta.3

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.

Potentially problematic release.


This version of onflyt-cli might be problematic. Click here for more details.

Files changed (67) hide show
  1. package/dist/App.d.ts +3 -0
  2. package/dist/App.js +8 -0
  3. package/dist/commands/credits.d.ts +3 -0
  4. package/dist/commands/credits.js +101 -0
  5. package/dist/commands/delete.d.ts +7 -0
  6. package/dist/commands/delete.js +220 -0
  7. package/dist/commands/deploy.d.ts +6 -0
  8. package/dist/commands/deploy.js +715 -0
  9. package/dist/commands/deployments.d.ts +6 -0
  10. package/dist/commands/deployments.js +225 -0
  11. package/dist/commands/help.d.ts +3 -0
  12. package/dist/commands/help.js +76 -0
  13. package/dist/commands/init.d.ts +11 -0
  14. package/dist/commands/init.js +422 -0
  15. package/dist/commands/login.d.ts +6 -0
  16. package/dist/commands/login.js +150 -0
  17. package/dist/commands/logout.d.ts +3 -0
  18. package/dist/commands/logout.js +19 -0
  19. package/dist/commands/logs.d.ts +7 -0
  20. package/dist/commands/logs.js +307 -0
  21. package/dist/commands/projects.d.ts +3 -0
  22. package/dist/commands/projects.js +203 -0
  23. package/dist/commands/rollback.d.ts +6 -0
  24. package/dist/commands/rollback.js +316 -0
  25. package/dist/commands/teams.d.ts +3 -0
  26. package/dist/commands/teams.js +81 -0
  27. package/dist/commands/whoami.d.ts +3 -0
  28. package/dist/commands/whoami.js +34 -0
  29. package/dist/components/Loading.d.ts +13 -0
  30. package/dist/components/Loading.js +42 -0
  31. package/dist/index.d.ts +1 -0
  32. package/dist/index.js +77 -116
  33. package/dist/lib/api.d.ts +27 -0
  34. package/dist/lib/api.js +109 -0
  35. package/dist/lib/config.d.ts +32 -0
  36. package/dist/lib/config.js +52 -0
  37. package/dist/lib/deploy-api.d.ts +97 -0
  38. package/dist/lib/deploy-api.js +335 -0
  39. package/dist/lib/deploy.d.ts +36 -0
  40. package/dist/lib/deploy.js +181 -0
  41. package/dist/lib/framework.d.ts +27 -0
  42. package/dist/lib/framework.js +184 -0
  43. package/dist/lib/git.d.ts +25 -0
  44. package/dist/lib/git.js +149 -0
  45. package/dist/lib/scaffold.d.ts +21 -0
  46. package/dist/lib/scaffold.js +190 -0
  47. package/dist/shared/frameworks/registry.d.ts +21 -0
  48. package/dist/shared/frameworks/registry.js +196 -0
  49. package/dist/shared/index.d.ts +4 -0
  50. package/dist/shared/index.js +4 -0
  51. package/dist/shared/limits.d.ts +16 -0
  52. package/dist/shared/limits.js +44 -0
  53. package/dist/shared/pricing.d.ts +2 -0
  54. package/dist/shared/pricing.js +7 -0
  55. package/dist/shared/templates/registry.d.ts +9 -0
  56. package/dist/shared/templates/registry.js +47 -0
  57. package/package.json +2 -3
  58. package/src/App.tsx +1 -1
  59. package/src/commands/deploy.tsx +1 -1
  60. package/src/commands/help.tsx +1 -1
  61. package/src/commands/init.tsx +1 -1
  62. package/src/commands/projects.tsx +1 -1
  63. package/src/components/Loading.tsx +1 -1
  64. package/src/index.tsx +1 -1
  65. package/src/lib/deploy-api.ts +3 -3
  66. package/src/lib/framework.ts +2 -2
  67. package/src/lib/shared.ts +350 -0
@@ -0,0 +1,307 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import { Text, Box, useInput } from "ink";
3
+ import { isLoggedIn, getConfig } from "../lib/config.js";
4
+ import { api } from "../lib/api.js";
5
+ import { Logo } from "../components/Loading.js";
6
+ import Spinner from "ink-spinner";
7
+ const Logs = ({ deploymentId, live = false }) => {
8
+ const [step, setStep] = useState("loading");
9
+ const [teams, setTeams] = useState([]);
10
+ const [projects, setProjects] = useState([]);
11
+ const [deployments, setDeployments] = useState([]);
12
+ const [selectedTeamIndex, setSelectedTeamIndex] = useState(0);
13
+ const [selectedProjectIndex, setSelectedProjectIndex] = useState(0);
14
+ const [selectedDeployIndex, setSelectedDeployIndex] = useState(0);
15
+ const [targetProject, setTargetProject] = useState(null);
16
+ const [targetDeploymentId, setTargetDeploymentId] = useState(null);
17
+ const [logs, setLogs] = useState([]);
18
+ const [errorMsg, setErrorMsg] = useState("");
19
+ const [dotCount, setDotCount] = useState(0);
20
+ useEffect(() => {
21
+ const handleSigInt = () => process.exit(0);
22
+ process.on("SIGINT", handleSigInt);
23
+ return () => {
24
+ process.off("SIGINT", handleSigInt);
25
+ };
26
+ }, []);
27
+ useEffect(() => {
28
+ if (step === "done") {
29
+ const timer = setTimeout(() => process.exit(0), 500);
30
+ return () => clearTimeout(timer);
31
+ }
32
+ }, [step]);
33
+ useInput((input, key) => {
34
+ if (input === "q" || input === "Q" || (key.ctrl && input === "c")) {
35
+ process.exit(0);
36
+ }
37
+ if (step === "team") {
38
+ if (key.upArrow) {
39
+ setSelectedTeamIndex((i) => Math.max(0, i - 1));
40
+ }
41
+ else if (key.downArrow) {
42
+ setSelectedTeamIndex((i) => Math.min(teams.length - 1, i + 1));
43
+ }
44
+ else if (key.return) {
45
+ setStep("loading-projects");
46
+ loadProjects(teams[selectedTeamIndex].team.id);
47
+ }
48
+ }
49
+ if (step === "project") {
50
+ if (key.upArrow) {
51
+ setSelectedProjectIndex((i) => Math.max(0, i - 1));
52
+ }
53
+ else if (key.downArrow) {
54
+ setSelectedProjectIndex((i) => Math.min(projects.length - 1, i + 1));
55
+ }
56
+ else if (key.return) {
57
+ setStep("loading-deployments");
58
+ loadDeployments(projects[selectedProjectIndex]);
59
+ }
60
+ else if (key.escape) {
61
+ setStep("team");
62
+ }
63
+ }
64
+ if (step === "deploy") {
65
+ if (key.upArrow) {
66
+ setSelectedDeployIndex((i) => Math.max(0, i - 1));
67
+ }
68
+ else if (key.downArrow) {
69
+ setSelectedDeployIndex((i) => Math.min(deployments.length - 1, i + 1));
70
+ }
71
+ else if (key.return) {
72
+ const dep = deployments[selectedDeployIndex];
73
+ setTargetDeploymentId(dep.id);
74
+ setTargetProject(targetProject);
75
+ if (live) {
76
+ startLiveStream(dep.id);
77
+ }
78
+ else {
79
+ fetchStoredLogs(dep.id);
80
+ }
81
+ }
82
+ else if (key.escape) {
83
+ setStep("project");
84
+ }
85
+ }
86
+ });
87
+ useEffect(() => {
88
+ if (step !== "streaming")
89
+ return;
90
+ const interval = setInterval(() => {
91
+ setDotCount((c) => (c + 1) % 4);
92
+ }, 500);
93
+ return () => clearInterval(interval);
94
+ }, [step]);
95
+ useEffect(() => {
96
+ if (!isLoggedIn()) {
97
+ setErrorMsg("Not logged in. Run 'onflyt login' first.");
98
+ setStep("error");
99
+ return;
100
+ }
101
+ if (deploymentId) {
102
+ setTargetDeploymentId(deploymentId);
103
+ if (live) {
104
+ startLiveStream(deploymentId);
105
+ }
106
+ else {
107
+ fetchStoredLogs(deploymentId);
108
+ }
109
+ return;
110
+ }
111
+ loadTeams();
112
+ }, []);
113
+ const loadTeams = async () => {
114
+ try {
115
+ const config = getConfig();
116
+ api.setToken(config.token);
117
+ const meData = await api.get("/auth/me");
118
+ const userTeams = meData.teams || [];
119
+ if (userTeams.length === 0) {
120
+ setErrorMsg("No teams found");
121
+ setStep("error");
122
+ return;
123
+ }
124
+ setTeams(userTeams);
125
+ if (userTeams.length === 1) {
126
+ setSelectedTeamIndex(0);
127
+ setStep("loading-projects");
128
+ loadProjects(userTeams[0].team.id);
129
+ }
130
+ else {
131
+ setStep("team");
132
+ }
133
+ }
134
+ catch (err) {
135
+ setErrorMsg(err.message);
136
+ setStep("error");
137
+ }
138
+ };
139
+ const loadProjects = async (teamId) => {
140
+ try {
141
+ const projectsRes = await api.get(`/projects/team/${teamId}`);
142
+ const teamProjects = projectsRes.projects || [];
143
+ if (teamProjects.length === 0) {
144
+ setErrorMsg("No projects found in this team");
145
+ setStep("error");
146
+ return;
147
+ }
148
+ setProjects(teamProjects);
149
+ setSelectedProjectIndex(0);
150
+ setStep("project");
151
+ }
152
+ catch (err) {
153
+ setErrorMsg(err.message);
154
+ setStep("error");
155
+ }
156
+ };
157
+ const loadDeployments = async (project) => {
158
+ try {
159
+ setTargetProject(project);
160
+ const depsRes = await api.get(`/deployments/${project.id}?limit=50`);
161
+ const allDeployments = depsRes.deployments || [];
162
+ if (allDeployments.length === 0) {
163
+ setErrorMsg("No deployments found for this project");
164
+ setStep("error");
165
+ return;
166
+ }
167
+ setDeployments(allDeployments);
168
+ setSelectedDeployIndex(0);
169
+ setStep("deploy");
170
+ }
171
+ catch (err) {
172
+ setErrorMsg(err.message);
173
+ setStep("error");
174
+ }
175
+ };
176
+ const startLiveStream = (depId) => {
177
+ setStep("streaming");
178
+ setLogs([]);
179
+ import("../lib/deploy-api.js").then(({ streamLogs }) => {
180
+ const cancel = streamLogs(depId, (log) => {
181
+ setLogs((prev) => [...prev.slice(-500), log]);
182
+ }, () => {
183
+ console.log("\n\x1b[33m⚠ Live logs stream ended\x1b[0m");
184
+ setStep("done");
185
+ });
186
+ return () => {
187
+ cancel();
188
+ };
189
+ });
190
+ };
191
+ const fetchStoredLogs = (depId) => {
192
+ setStep("loading");
193
+ import("../lib/deploy-api.js").then(({ getStoredLogs }) => {
194
+ getStoredLogs(depId, { limit: 200 })
195
+ .then((result) => {
196
+ setLogs(result.logs.map((l) => `[${new Date(l.timestamp).toISOString()}] [${l.level.toUpperCase()}] ${l.message}`));
197
+ setStep("displaying");
198
+ })
199
+ .catch((err) => {
200
+ setErrorMsg(err.message || "Failed to fetch logs");
201
+ setStep("error");
202
+ });
203
+ });
204
+ };
205
+ if (step === "loading" ||
206
+ step === "loading-projects" ||
207
+ step === "loading-deployments") {
208
+ return (React.createElement(Box, { flexDirection: "column", padding: 1 },
209
+ React.createElement(Logo, null),
210
+ React.createElement(Box, { marginTop: 1 },
211
+ React.createElement(Text, { bold: true }, "View Logs")),
212
+ React.createElement(Box, { marginTop: 1 },
213
+ React.createElement(Text, { dimColor: true },
214
+ "Loading",
215
+ step === "loading-projects"
216
+ ? " projects..."
217
+ : step === "loading-deployments"
218
+ ? " deployments..."
219
+ : "...")),
220
+ React.createElement(Box, { marginTop: 1 },
221
+ React.createElement(Text, null,
222
+ React.createElement(Spinner, null)))));
223
+ }
224
+ if (step === "error") {
225
+ return (React.createElement(Box, { flexDirection: "column" },
226
+ React.createElement(Logo, null),
227
+ React.createElement(Box, { marginTop: 1 },
228
+ React.createElement(Text, { bold: true, color: "red" }, "\u2716 Error")),
229
+ React.createElement(Box, { marginTop: 1 },
230
+ React.createElement(Text, { color: "red" }, errorMsg))));
231
+ }
232
+ if (step === "team") {
233
+ return (React.createElement(Box, { flexDirection: "column", padding: 1 },
234
+ React.createElement(Logo, null),
235
+ React.createElement(Box, { marginTop: 1 },
236
+ React.createElement(Text, { bold: true }, "View Logs")),
237
+ React.createElement(Box, { marginTop: 1 },
238
+ React.createElement(Text, { dimColor: true }, "Step 1/3: Select Team (\u2191\u2193 navigate, Enter select)")),
239
+ React.createElement(Box, { marginTop: 1, flexDirection: "column" }, teams.map((t, idx) => (React.createElement(Box, { key: t.team.id, marginTop: 1 },
240
+ React.createElement(Text, { color: idx === selectedTeamIndex ? "cyan" : "gray" }, idx === selectedTeamIndex ? "▶ " : " "),
241
+ React.createElement(Text, { bold: idx === selectedTeamIndex }, t.team.name)))))));
242
+ }
243
+ if (step === "project") {
244
+ return (React.createElement(Box, { flexDirection: "column", padding: 1 },
245
+ React.createElement(Logo, null),
246
+ React.createElement(Box, { marginTop: 1 },
247
+ React.createElement(Text, { bold: true }, "View Logs")),
248
+ React.createElement(Box, { marginTop: 1 },
249
+ React.createElement(Text, { dimColor: true },
250
+ "Step 2/3: Select Project - ",
251
+ teams[selectedTeamIndex]?.team.name)),
252
+ React.createElement(Box, null,
253
+ React.createElement(Text, { dimColor: true }, "(\u2191\u2193 navigate, Enter select, Esc go back)")),
254
+ React.createElement(Box, { marginTop: 1, flexDirection: "column" }, projects.map((p, idx) => (React.createElement(Box, { key: p.id, marginTop: 1 },
255
+ React.createElement(Text, { color: idx === selectedProjectIndex ? "cyan" : "gray" }, idx === selectedProjectIndex ? "▶ " : " "),
256
+ React.createElement(Text, { bold: idx === selectedProjectIndex }, p.name)))))));
257
+ }
258
+ if (step === "deploy") {
259
+ const formatDate = (dateStr) => {
260
+ const date = new Date(dateStr);
261
+ return date.toLocaleDateString() + " " + date.toLocaleTimeString();
262
+ };
263
+ return (React.createElement(Box, { flexDirection: "column", padding: 1 },
264
+ React.createElement(Logo, null),
265
+ React.createElement(Box, { marginTop: 1 },
266
+ React.createElement(Text, { bold: true }, "View Logs")),
267
+ React.createElement(Box, { marginTop: 1 },
268
+ React.createElement(Text, { dimColor: true },
269
+ "Step 3/3: Select Deployment - ",
270
+ targetProject?.name)),
271
+ React.createElement(Box, null,
272
+ React.createElement(Text, { dimColor: true }, "(\u2191\u2193 navigate, Enter select, Esc go back)")),
273
+ React.createElement(Box, { marginTop: 1, flexDirection: "column" }, deployments.map((dep, idx) => (React.createElement(Box, { key: dep.id, marginTop: 1, flexDirection: "column" },
274
+ React.createElement(Box, null,
275
+ React.createElement(Text, { color: idx === selectedDeployIndex ? "cyan" : "gray" }, idx === selectedDeployIndex ? "▶ " : " "),
276
+ React.createElement(Text, { bold: idx === selectedDeployIndex }, dep.commitMessage || "Manual Upload"),
277
+ React.createElement(Text, { dimColor: true },
278
+ " [",
279
+ dep.status,
280
+ "]")),
281
+ React.createElement(Box, { marginLeft: 2 },
282
+ React.createElement(Text, { dimColor: true },
283
+ "ID: ",
284
+ dep.id)),
285
+ React.createElement(Box, { marginLeft: 2 },
286
+ React.createElement(Text, { dimColor: true }, formatDate(dep.createdAt)))))))));
287
+ }
288
+ const dots = ".".repeat(dotCount);
289
+ return (React.createElement(Box, { flexDirection: "column", padding: 1 },
290
+ React.createElement(Logo, null),
291
+ React.createElement(Box, { marginTop: 1 },
292
+ React.createElement(Text, { bold: true, color: "cyan" }, "Deployment:"),
293
+ React.createElement(Text, null,
294
+ " ",
295
+ targetDeploymentId),
296
+ step === "streaming" && React.createElement(Text, { dimColor: true },
297
+ " ",
298
+ dots),
299
+ step === "streaming" && (React.createElement(Box, { marginLeft: 2 },
300
+ React.createElement(Text, { dimColor: true }, "(Ctrl+C to exit)")))),
301
+ React.createElement(Box, { marginTop: 1 },
302
+ React.createElement(Text, { dimColor: true }, live
303
+ ? "Streaming live logs..."
304
+ : `Showing last ${logs.length} log entries`)),
305
+ React.createElement(Box, { marginTop: 1, flexDirection: "column", borderStyle: "round", borderDimColor: true, paddingX: 1 }, logs.length === 0 ? (React.createElement(Text, { dimColor: true }, "No logs available")) : (logs.map((log, idx) => (React.createElement(Text, { key: idx, wrap: "wrap" }, log)))))));
306
+ };
307
+ export default Logs;
@@ -0,0 +1,3 @@
1
+ import React from "react";
2
+ declare const ProjectsList: () => React.JSX.Element;
3
+ export default ProjectsList;
@@ -0,0 +1,203 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import { Text, Box, useInput } from "ink";
3
+ import { isLoggedIn, getConfig } from "../lib/config.js";
4
+ import { api } from "../lib/api.js";
5
+ import { Logo } from "../components/Loading.js";
6
+ import Spinner from "ink-spinner";
7
+ import { FRAMEWORKS } from "../shared";
8
+ const ProjectsList = () => {
9
+ const [step, setStep] = useState("loading");
10
+ const [teams, setTeams] = useState([]);
11
+ const [projects, setProjects] = useState([]);
12
+ const [selectedTeamIndex, setSelectedTeamIndex] = useState(0);
13
+ const [selectedProjectIndex, setSelectedProjectIndex] = useState(0);
14
+ const [errorMsg, setErrorMsg] = useState("");
15
+ useEffect(() => {
16
+ const handleSigInt = () => process.exit(0);
17
+ process.on("SIGINT", handleSigInt);
18
+ return () => {
19
+ process.off("SIGINT", handleSigInt);
20
+ };
21
+ }, []);
22
+ useInput((input, key) => {
23
+ if (input === "q" || input === "Q" || (key.ctrl && input === "c")) {
24
+ process.exit(0);
25
+ }
26
+ if (step === "team") {
27
+ if (key.upArrow) {
28
+ setSelectedTeamIndex((i) => Math.max(0, i - 1));
29
+ }
30
+ else if (key.downArrow) {
31
+ setSelectedTeamIndex((i) => Math.min(teams.length - 1, i + 1));
32
+ }
33
+ else if (key.return) {
34
+ setStep("loading-projects");
35
+ loadProjects(teams[selectedTeamIndex].team.id);
36
+ }
37
+ }
38
+ if (step === "project") {
39
+ if (key.upArrow) {
40
+ setSelectedProjectIndex((i) => Math.max(0, i - 1));
41
+ }
42
+ else if (key.downArrow) {
43
+ setSelectedProjectIndex((i) => Math.min(projects.length - 1, i + 1));
44
+ }
45
+ else if (key.return) {
46
+ setStep("display");
47
+ }
48
+ else if (key.escape) {
49
+ setStep("team");
50
+ }
51
+ }
52
+ });
53
+ useEffect(() => {
54
+ if (!isLoggedIn()) {
55
+ setErrorMsg("Not logged in. Run 'onflyt login' first.");
56
+ setStep("error");
57
+ return;
58
+ }
59
+ loadTeams();
60
+ }, []);
61
+ const loadTeams = async () => {
62
+ try {
63
+ const config = getConfig();
64
+ api.setToken(config.token);
65
+ const meData = await api.get("/auth/me");
66
+ const userTeams = meData.teams || [];
67
+ if (userTeams.length === 0) {
68
+ setErrorMsg("No teams found");
69
+ setStep("error");
70
+ return;
71
+ }
72
+ setTeams(userTeams);
73
+ if (userTeams.length === 1) {
74
+ setSelectedTeamIndex(0);
75
+ setStep("loading-projects");
76
+ loadProjects(userTeams[0].team.id);
77
+ }
78
+ else {
79
+ setStep("team");
80
+ }
81
+ }
82
+ catch (err) {
83
+ setErrorMsg(err.message);
84
+ setStep("error");
85
+ }
86
+ };
87
+ const loadProjects = async (teamId) => {
88
+ try {
89
+ const projectsRes = await api.get(`/projects/team/${teamId}`);
90
+ const teamProjects = projectsRes.projects || [];
91
+ setProjects(teamProjects);
92
+ setSelectedProjectIndex(0);
93
+ setStep("project");
94
+ }
95
+ catch (err) {
96
+ setErrorMsg(err.message);
97
+ setStep("error");
98
+ }
99
+ };
100
+ if (step === "loading" || step === "loading-projects") {
101
+ return (React.createElement(Box, { flexDirection: "column", padding: 1 },
102
+ React.createElement(Logo, null),
103
+ React.createElement(Box, { marginTop: 1 },
104
+ React.createElement(Text, { bold: true }, "Projects")),
105
+ React.createElement(Box, { marginTop: 1 },
106
+ React.createElement(Text, { dimColor: true },
107
+ "Loading",
108
+ step === "loading-projects" ? " projects..." : "...")),
109
+ React.createElement(Box, { marginTop: 1 },
110
+ React.createElement(Text, null,
111
+ React.createElement(Spinner, null)))));
112
+ }
113
+ if (step === "error") {
114
+ return (React.createElement(Box, { flexDirection: "column" },
115
+ React.createElement(Logo, null),
116
+ React.createElement(Box, { marginTop: 1 },
117
+ React.createElement(Text, { bold: true, color: "red" }, "\u2716 Error")),
118
+ React.createElement(Box, { marginTop: 1 },
119
+ React.createElement(Text, { color: "red" }, errorMsg))));
120
+ }
121
+ if (step === "team") {
122
+ return (React.createElement(Box, { flexDirection: "column", padding: 1 },
123
+ React.createElement(Logo, null),
124
+ React.createElement(Box, { marginTop: 1 },
125
+ React.createElement(Text, { bold: true }, "Projects")),
126
+ React.createElement(Box, { marginTop: 1 },
127
+ React.createElement(Text, { dimColor: true }, "Step 1/2: Select Team (\u2191\u2193 navigate, Enter select)")),
128
+ React.createElement(Box, { marginTop: 1, flexDirection: "column" }, teams.map((t, idx) => (React.createElement(Box, { key: t.team.id, marginTop: 1 },
129
+ React.createElement(Text, { color: idx === selectedTeamIndex ? "cyan" : "gray" }, idx === selectedTeamIndex ? "▶ " : " "),
130
+ React.createElement(Text, { bold: idx === selectedTeamIndex }, t.team.name)))))));
131
+ }
132
+ if (step === "project") {
133
+ return (React.createElement(Box, { flexDirection: "column", padding: 1 },
134
+ React.createElement(Logo, null),
135
+ React.createElement(Box, { marginTop: 1 },
136
+ React.createElement(Text, { bold: true }, "Projects")),
137
+ React.createElement(Box, { marginTop: 1 },
138
+ React.createElement(Text, { dimColor: true },
139
+ "Step 2/2: Select Project - ",
140
+ teams[selectedTeamIndex]?.team.name)),
141
+ React.createElement(Box, null,
142
+ React.createElement(Text, { dimColor: true }, "(\u2191\u2193 navigate, Enter view details, Esc go back)")),
143
+ React.createElement(Box, { marginTop: 1, flexDirection: "column" }, projects.length === 0 ? (React.createElement(Text, { dimColor: true }, "No projects in this team")) : (projects.map((p, idx) => (React.createElement(Box, { key: p.id, marginTop: 1 },
144
+ React.createElement(Text, { color: idx === selectedProjectIndex ? "cyan" : "gray" }, idx === selectedProjectIndex ? "▶ " : " "),
145
+ React.createElement(Text, { bold: idx === selectedProjectIndex }, p.name),
146
+ React.createElement(Text, { dimColor: true },
147
+ " ",
148
+ "(",
149
+ FRAMEWORKS[p.framework]?.label || p.framework,
150
+ ")"),
151
+ React.createElement(Text, { dimColor: true },
152
+ " ",
153
+ "- ",
154
+ p.status === "active" ? "●" : "○",
155
+ " ",
156
+ p.status))))))));
157
+ }
158
+ const selectedProject = projects[selectedProjectIndex];
159
+ return (React.createElement(Box, { flexDirection: "column", padding: 1 },
160
+ React.createElement(Logo, null),
161
+ React.createElement(Box, { marginTop: 1 },
162
+ React.createElement(Text, { bold: true }, "Project Details")),
163
+ React.createElement(Box, null,
164
+ React.createElement(Text, { dimColor: true },
165
+ teams[selectedTeamIndex]?.team.name,
166
+ " / ",
167
+ selectedProject?.name)),
168
+ selectedProject && (React.createElement(Box, { marginTop: 1, flexDirection: "column", borderStyle: "round", borderDimColor: true, paddingX: 1 },
169
+ React.createElement(Box, { marginTop: 1 },
170
+ React.createElement(Text, { bold: true }, "Name:"),
171
+ React.createElement(Text, null,
172
+ " ",
173
+ selectedProject.name)),
174
+ React.createElement(Box, { marginTop: 1 },
175
+ React.createElement(Text, { bold: true }, "Framework:"),
176
+ React.createElement(Text, null,
177
+ " ",
178
+ FRAMEWORKS[selectedProject.framework]?.label ||
179
+ selectedProject.framework)),
180
+ React.createElement(Box, { marginTop: 1 },
181
+ React.createElement(Text, { bold: true }, "Status:"),
182
+ React.createElement(Text, null,
183
+ " ",
184
+ selectedProject.status)),
185
+ React.createElement(Box, { marginTop: 1 },
186
+ React.createElement(Text, { bold: true }, "ID:"),
187
+ React.createElement(Text, { dimColor: true },
188
+ " ",
189
+ selectedProject.id)),
190
+ selectedProject.gitRepoUrl && (React.createElement(Box, { marginTop: 1 },
191
+ React.createElement(Text, { bold: true }, "Repository:"),
192
+ React.createElement(Text, { color: "cyan" },
193
+ " ",
194
+ selectedProject.gitRepoUrl))),
195
+ selectedProject.outputDirectory && (React.createElement(Box, { marginTop: 1 },
196
+ React.createElement(Text, { bold: true }, "Output:"),
197
+ React.createElement(Text, { dimColor: true },
198
+ " ",
199
+ selectedProject.outputDirectory))))),
200
+ React.createElement(Box, { marginTop: 1 },
201
+ React.createElement(Text, { dimColor: true }, "\u2191\u2193 navigate projects | Esc go back"))));
202
+ };
203
+ export default ProjectsList;
@@ -0,0 +1,6 @@
1
+ import React from "react";
2
+ interface RollbackProps {
3
+ deploymentId?: string;
4
+ }
5
+ declare const Rollback: React.FC<RollbackProps>;
6
+ export default Rollback;