Skip to content

Commit 4c65dd2

Browse files
committed
feat: install and setup terminal automatically for first time
1 parent d9f292d commit 4c65dd2

File tree

2 files changed

+151
-3
lines changed

2 files changed

+151
-3
lines changed

src/components/terminal/terminal.js

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,32 @@ export default class TerminalComponent {
190190
}
191191

192192
try {
193+
// Check if terminal is installed before starting AXS
194+
if (!(await Terminal.isInstalled())) {
195+
throw new Error(
196+
"Terminal not installed. Please install terminal first.",
197+
);
198+
}
199+
193200
// Start AXS if not running
194201
if (!(await Terminal.isAxsRunning())) {
195-
await Terminal.startAxs();
196-
// Wait a bit for server to start
197-
await new Promise((resolve) => setTimeout(resolve, 2000));
202+
await Terminal.startAxs(false, () => {}, console.error);
203+
204+
// Check if AXS started with interval polling
205+
const maxRetries = 10;
206+
let retries = 0;
207+
while (retries < maxRetries) {
208+
await new Promise((resolve) => setTimeout(resolve, 1000));
209+
if (await Terminal.isAxsRunning()) {
210+
break;
211+
}
212+
retries++;
213+
}
214+
215+
// If AXS still not running after retries, throw error
216+
if (!(await Terminal.isAxsRunning())) {
217+
throw new Error("Failed to start AXS server after multiple attempts");
218+
}
198219
}
199220

200221
const requestBody = {

src/components/terminal/terminalManager.js

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ class TerminalManager {
2323
const terminalId = `terminal_${++this.terminalCounter}`;
2424
const terminalName = options.name || `Terminal ${this.terminalCounter}`;
2525

26+
// Check if terminal is installed before proceeding
27+
if (options.serverMode !== false) {
28+
const installationResult = await this.checkAndInstallTerminal();
29+
if (!installationResult.success) {
30+
throw new Error(installationResult.error);
31+
}
32+
}
33+
2634
// Create terminal component
2735
const terminalComponent = new TerminalComponent({
2836
serverMode: options.serverMode !== false,
@@ -101,6 +109,123 @@ class TerminalManager {
101109
}
102110
}
103111

112+
/**
113+
* Check if terminal is installed and install if needed
114+
* @returns {Promise<{success: boolean, error?: string}>}
115+
*/
116+
async checkAndInstallTerminal() {
117+
try {
118+
// Check if terminal is already installed
119+
const isInstalled = await Terminal.isInstalled();
120+
if (isInstalled) {
121+
return { success: true };
122+
}
123+
124+
// Check if terminal is supported on this device
125+
const isSupported = await Terminal.isSupported();
126+
if (!isSupported) {
127+
return {
128+
success: false,
129+
error: "Terminal is not supported on this device architecture",
130+
};
131+
}
132+
133+
// Create installation progress terminal
134+
const installTerminal = await this.createInstallationTerminal();
135+
136+
// Install terminal with progress logging
137+
await Terminal.install(
138+
(message) => {
139+
installTerminal.component.write(`${message}\r\n`);
140+
},
141+
(error) => {
142+
installTerminal.component.write(`\x1b[31mError: ${error}\x1b[0m\r\n`);
143+
},
144+
);
145+
return { success: true };
146+
} catch (error) {
147+
console.error("Terminal installation failed:", error);
148+
return {
149+
success: false,
150+
error: `Terminal installation failed: ${error.message}`,
151+
};
152+
}
153+
}
154+
155+
/**
156+
* Create a terminal for showing installation progress
157+
* @returns {Promise<object>} Installation terminal instance
158+
*/
159+
async createInstallationTerminal() {
160+
const terminalId = `install_terminal_${++this.terminalCounter}`;
161+
const terminalName = "Terminal Installation";
162+
163+
// Create terminal component in local mode (no server needed)
164+
const terminalComponent = new TerminalComponent({
165+
serverMode: false,
166+
});
167+
168+
// Create container
169+
const terminalContainer = tag("div", {
170+
className: "terminal-content",
171+
id: `terminal-${terminalId}`,
172+
});
173+
174+
// Terminal styles
175+
const terminalStyles = this.getTerminalStyles();
176+
const terminalStyle = tag("style", {
177+
textContent: terminalStyles,
178+
});
179+
document.body.appendChild(terminalStyle);
180+
181+
// Create EditorFile for terminal
182+
const terminalFile = new EditorFile(terminalName, {
183+
type: "terminal",
184+
content: terminalContainer,
185+
tabIcon: "icon download",
186+
render: true,
187+
});
188+
189+
// Wait for tab creation and setup
190+
const terminalInstance = await new Promise((resolve, reject) => {
191+
setTimeout(async () => {
192+
try {
193+
// Mount terminal component
194+
terminalComponent.mount(terminalContainer);
195+
196+
// Write initial message
197+
terminalComponent.write("🚀 Installing Terminal Environment...\r\n");
198+
terminalComponent.write(
199+
"This may take a few minutes depending on your connection.\r\n\r\n",
200+
);
201+
202+
// Setup event handlers
203+
this.setupTerminalHandlers(
204+
terminalFile,
205+
terminalComponent,
206+
terminalId,
207+
);
208+
209+
const instance = {
210+
id: terminalId,
211+
name: terminalName,
212+
component: terminalComponent,
213+
file: terminalFile,
214+
container: terminalContainer,
215+
};
216+
217+
this.terminals.set(terminalId, instance);
218+
resolve(instance);
219+
} catch (error) {
220+
console.error("Failed to create installation terminal:", error);
221+
reject(error);
222+
}
223+
}, 100);
224+
});
225+
226+
return terminalInstance;
227+
}
228+
104229
/**
105230
* Setup terminal event handlers
106231
* @param {EditorFile} terminalFile - Terminal file instance
@@ -150,6 +275,8 @@ class TerminalManager {
150275
terminalComponent.onError = (error) => {
151276
console.error(`Terminal ${terminalId} error:`, error);
152277
window.toast?.("Terminal connection error");
278+
// Close the terminal tab on error
279+
this.closeTerminal(terminalId);
153280
};
154281

155282
terminalComponent.onTitleChange = (title) => {

0 commit comments

Comments
 (0)