genbox 1.0.231 → 1.0.232

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.
package/dist/index.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genbox",
3
- "version": "1.0.231",
3
+ "version": "1.0.232",
4
4
  "description": "Genbox CLI - AI-Powered Development Environments",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,14 +0,0 @@
1
- "use strict";
2
- /**
3
- * Dashboard Hooks Barrel Export
4
- */
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.useGenboxActions = exports.useSessionActions = exports.useLiveOutput = exports.useSessionPoller = void 0;
7
- var useSessionPoller_1 = require("./useSessionPoller");
8
- Object.defineProperty(exports, "useSessionPoller", { enumerable: true, get: function () { return useSessionPoller_1.useSessionPoller; } });
9
- var useLiveOutput_1 = require("./useLiveOutput");
10
- Object.defineProperty(exports, "useLiveOutput", { enumerable: true, get: function () { return useLiveOutput_1.useLiveOutput; } });
11
- var useSessionActions_1 = require("./useSessionActions");
12
- Object.defineProperty(exports, "useSessionActions", { enumerable: true, get: function () { return useSessionActions_1.useSessionActions; } });
13
- var useGenboxActions_1 = require("./useGenboxActions");
14
- Object.defineProperty(exports, "useGenboxActions", { enumerable: true, get: function () { return useGenboxActions_1.useGenboxActions; } });
@@ -1,100 +0,0 @@
1
- "use strict";
2
- /**
3
- * Genbox Actions Hook
4
- * Handles create, destroy, extend operations
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.useGenboxActions = useGenboxActions;
8
- const react_1 = require("react");
9
- const child_process_1 = require("child_process");
10
- const util_1 = require("util");
11
- const dashboard_1 = require("../store/dashboard");
12
- const api_1 = require("../../../api");
13
- const execAsync = (0, util_1.promisify)(child_process_1.exec);
14
- function useGenboxActions() {
15
- const { setModal } = (0, dashboard_1.useDashboardStore)();
16
- /**
17
- * Create a new genbox
18
- * Opens the creation wizard
19
- */
20
- const createGenbox = (0, react_1.useCallback)(async (options) => {
21
- try {
22
- // This will exit the dashboard and run the wizard
23
- // Return false to indicate dashboard should exit
24
- return false;
25
- }
26
- catch {
27
- return false;
28
- }
29
- }, []);
30
- /**
31
- * Destroy a genbox
32
- */
33
- const destroyGenbox = (0, react_1.useCallback)(async (genbox) => {
34
- try {
35
- await (0, api_1.fetchApi)(`/genboxes/${genbox.id}`, {
36
- method: 'DELETE',
37
- });
38
- return true;
39
- }
40
- catch {
41
- return false;
42
- }
43
- }, []);
44
- /**
45
- * Extend genbox time
46
- */
47
- const extendGenbox = (0, react_1.useCallback)(async (genbox, hours = 1) => {
48
- try {
49
- await (0, api_1.fetchApi)(`/genboxes/${genbox.id}/extend`, {
50
- method: 'POST',
51
- body: JSON.stringify({ hours }),
52
- });
53
- return true;
54
- }
55
- catch {
56
- return false;
57
- }
58
- }, []);
59
- /**
60
- * Connect to genbox via SSH
61
- */
62
- const connectSSH = (0, react_1.useCallback)((genbox) => {
63
- return {
64
- connect: () => {
65
- try {
66
- (0, child_process_1.execSync)(`ssh genbox-${genbox.name}`, { stdio: 'inherit' });
67
- }
68
- catch {
69
- // Normal exit
70
- }
71
- },
72
- };
73
- }, []);
74
- /**
75
- * Show destroy confirmation modal
76
- */
77
- const confirmDestroyGenbox = (0, react_1.useCallback)((genbox, onConfirm) => {
78
- setModal({
79
- type: 'confirm',
80
- title: 'Destroy Genbox',
81
- message: `Are you sure you want to destroy "${genbox.name}"?\nThis will terminate all running sessions.`,
82
- confirmLabel: 'Destroy',
83
- cancelLabel: 'Cancel',
84
- onConfirm: () => {
85
- destroyGenbox(genbox).then(() => {
86
- onConfirm();
87
- });
88
- setModal(null);
89
- },
90
- onCancel: () => setModal(null),
91
- });
92
- }, [setModal, destroyGenbox]);
93
- return {
94
- createGenbox,
95
- destroyGenbox,
96
- extendGenbox,
97
- connectSSH,
98
- confirmDestroyGenbox,
99
- };
100
- }
@@ -1,137 +0,0 @@
1
- "use strict";
2
- /**
3
- * Live Output Hook
4
- * Polls live terminal output for selected session
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.useLiveOutput = useLiveOutput;
8
- const react_1 = require("react");
9
- const child_process_1 = require("child_process");
10
- const util_1 = require("util");
11
- const dashboard_1 = require("../store/dashboard");
12
- const execAsync = (0, util_1.promisify)(child_process_1.exec);
13
- /**
14
- * Query terminal output from genbox via dtach typescript file
15
- */
16
- async function queryGenboxTerminalOutput(genboxName, sessionName, lines = 100) {
17
- try {
18
- const { stdout } = await execAsync(`ssh -o ConnectTimeout=2 -o BatchMode=yes genbox-${genboxName} '
19
- TYPESCRIPT_FILE="/home/dev/.genbox/typescript-${sessionName}"
20
- if [ -f "$TYPESCRIPT_FILE" ]; then
21
- tail -n ${lines} "$TYPESCRIPT_FILE" 2>/dev/null || cat "$TYPESCRIPT_FILE" 2>/dev/null
22
- else
23
- echo "No output captured yet"
24
- fi
25
- ' 2>/dev/null`, { encoding: 'utf8', timeout: 5000 });
26
- return cleanTerminalOutput(stdout);
27
- }
28
- catch {
29
- return '';
30
- }
31
- }
32
- /**
33
- * Query daemon events for activity log
34
- */
35
- async function queryGenboxDaemonEvents(genboxName, sessionName, count = 20) {
36
- try {
37
- const { stdout } = await execAsync(`ssh -o ConnectTimeout=2 -o BatchMode=yes genbox-${genboxName} '
38
- curl -s "http://127.0.0.1:47191/api/sessions/${sessionName}/events?limit=${count}" 2>/dev/null ||
39
- curl -s "http://127.0.0.1:47192/api/sessions/${sessionName}/events?limit=${count}" 2>/dev/null ||
40
- echo "[]"
41
- ' 2>/dev/null`, { encoding: 'utf8', timeout: 5000 });
42
- const events = JSON.parse(stdout.trim() || '[]');
43
- if (!Array.isArray(events))
44
- return [];
45
- return events.map((e) => ({
46
- timestamp: new Date(e.timestamp || e.createdAt || Date.now()),
47
- type: mapEventType(e.type || e.eventType),
48
- content: e.content || e.message || e.data?.toolName || 'Event',
49
- session: sessionName,
50
- }));
51
- }
52
- catch {
53
- return [];
54
- }
55
- }
56
- function mapEventType(type) {
57
- if (type?.includes('tool'))
58
- return 'tool';
59
- if (type?.includes('error'))
60
- return 'error';
61
- if (type?.includes('state'))
62
- return 'state';
63
- return 'message';
64
- }
65
- /**
66
- * Clean terminal output from dtach recording
67
- */
68
- function cleanTerminalOutput(output) {
69
- let cleaned = output
70
- .replace(/Script started on.*\n?/g, '')
71
- .replace(/Script done on.*\n?/g, '');
72
- // Fix broken ANSI codes
73
- cleaned = cleaned.replace(/(?<!\x1B)\[(\d+(?:;\d+)*)?m/g, '\x1B[$1m');
74
- // Find last complete screen frame
75
- const clearPatterns = ['\x1B[H\x1B[J', '\x1B[2J'];
76
- let lastClearIndex = -1;
77
- for (const pattern of clearPatterns) {
78
- const idx = cleaned.lastIndexOf(pattern);
79
- if (idx > lastClearIndex)
80
- lastClearIndex = idx + pattern.length;
81
- }
82
- if (lastClearIndex > 0) {
83
- cleaned = cleaned.substring(lastClearIndex);
84
- }
85
- // Remove control sequences but preserve basic text
86
- cleaned = cleaned
87
- .replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '')
88
- .replace(/\x1B\][^\x07]*\x07/g, '')
89
- .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, '');
90
- return cleaned;
91
- }
92
- /**
93
- * Hook for polling live terminal output
94
- */
95
- function useLiveOutput(intervalMs = 2000) {
96
- const pollerRef = (0, react_1.useRef)(null);
97
- const { setLiveOutput, addActivityEvent, getSelectedSession, viewMode } = (0, dashboard_1.useDashboardStore)();
98
- const pollOutput = (0, react_1.useCallback)(async () => {
99
- const session = getSelectedSession();
100
- if (!session || !session.genbox || session.type !== 'cloud') {
101
- return;
102
- }
103
- // Only poll if in split or live view
104
- const currentViewMode = dashboard_1.useDashboardStore.getState().viewMode;
105
- if (currentViewMode !== 'split' && currentViewMode !== 'live') {
106
- return;
107
- }
108
- try {
109
- const [output, events] = await Promise.all([
110
- queryGenboxTerminalOutput(session.genbox, session.name, 100),
111
- queryGenboxDaemonEvents(session.genbox, session.name, 10),
112
- ]);
113
- if (output) {
114
- setLiveOutput(output);
115
- }
116
- // Add new events to activity log (avoid duplicates)
117
- for (const event of events) {
118
- addActivityEvent(event);
119
- }
120
- }
121
- catch {
122
- // Ignore errors
123
- }
124
- }, [getSelectedSession, setLiveOutput, addActivityEvent]);
125
- (0, react_1.useEffect)(() => {
126
- // Initial poll
127
- pollOutput();
128
- // Set up polling
129
- pollerRef.current = setInterval(pollOutput, intervalMs);
130
- return () => {
131
- if (pollerRef.current) {
132
- clearInterval(pollerRef.current);
133
- }
134
- };
135
- }, [pollOutput, intervalMs]);
136
- return { pollOutput };
137
- }
@@ -1,224 +0,0 @@
1
- "use strict";
2
- /**
3
- * Session Actions Hook
4
- * Handles attach, send, kill operations
5
- */
6
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
- if (k2 === undefined) k2 = k;
8
- var desc = Object.getOwnPropertyDescriptor(m, k);
9
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
- desc = { enumerable: true, get: function() { return m[k]; } };
11
- }
12
- Object.defineProperty(o, k2, desc);
13
- }) : (function(o, m, k, k2) {
14
- if (k2 === undefined) k2 = k;
15
- o[k2] = m[k];
16
- }));
17
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
- Object.defineProperty(o, "default", { enumerable: true, value: v });
19
- }) : function(o, v) {
20
- o["default"] = v;
21
- });
22
- var __importStar = (this && this.__importStar) || (function () {
23
- var ownKeys = function(o) {
24
- ownKeys = Object.getOwnPropertyNames || function (o) {
25
- var ar = [];
26
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
- return ar;
28
- };
29
- return ownKeys(o);
30
- };
31
- return function (mod) {
32
- if (mod && mod.__esModule) return mod;
33
- var result = {};
34
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
- __setModuleDefault(result, mod);
36
- return result;
37
- };
38
- })();
39
- Object.defineProperty(exports, "__esModule", { value: true });
40
- exports.useSessionActions = useSessionActions;
41
- const react_1 = require("react");
42
- const child_process_1 = require("child_process");
43
- const util_1 = require("util");
44
- const path = __importStar(require("path"));
45
- const os = __importStar(require("os"));
46
- const dashboard_1 = require("../store/dashboard");
47
- const execAsync = (0, util_1.promisify)(child_process_1.exec);
48
- function getDtachSocketDir() {
49
- return path.join(os.homedir(), '.genbox', 'sockets');
50
- }
51
- function getRemoteDtachSocketDir() {
52
- return '/home/dev/.genbox/sockets';
53
- }
54
- /**
55
- * Get SSH key path
56
- */
57
- function getPrivateSshKeyPath() {
58
- const keyPath = path.join(os.homedir(), '.genbox', 'id_ed25519');
59
- return keyPath;
60
- }
61
- function useSessionActions() {
62
- const { setAttachedSession, setModal, getSelectedSession } = (0, dashboard_1.useDashboardStore)();
63
- /**
64
- * Attach to a session
65
- * Returns a function to spawn the attach process
66
- */
67
- const attachToSession = (0, react_1.useCallback)(async (session) => {
68
- const socketPath = session.type === 'cloud'
69
- ? `${getRemoteDtachSocketDir()}/${session.name}.sock`
70
- : path.join(getDtachSocketDir(), `${session.name}.sock`);
71
- if (session.type === 'cloud' && session.genbox) {
72
- // Return function to spawn SSH + dtach
73
- return {
74
- attach: () => {
75
- const keyPath = getPrivateSshKeyPath();
76
- const sshArgs = [
77
- '-t',
78
- '-i',
79
- keyPath,
80
- '-o',
81
- 'StrictHostKeyChecking=no',
82
- '-o',
83
- 'UserKnownHostsFile=/dev/null',
84
- '-o',
85
- 'LogLevel=ERROR',
86
- `genbox-${session.genbox}`,
87
- `dtach -a ${socketPath}`,
88
- ];
89
- // Use execSync to run in foreground
90
- try {
91
- (0, child_process_1.execSync)(`ssh ${sshArgs.join(' ')}`, { stdio: 'inherit' });
92
- }
93
- catch {
94
- // Detach is normal exit
95
- }
96
- },
97
- };
98
- }
99
- else if (session.type === 'native') {
100
- return {
101
- attach: () => {
102
- try {
103
- (0, child_process_1.execSync)(`dtach -a ${socketPath}`, { stdio: 'inherit' });
104
- }
105
- catch {
106
- // Detach is normal exit
107
- }
108
- },
109
- };
110
- }
111
- else if (session.type === 'docker') {
112
- const containerName = session.genbox || session.name;
113
- return {
114
- attach: () => {
115
- try {
116
- (0, child_process_1.execSync)(`docker exec -it ${containerName} dtach -a ${socketPath}`, {
117
- stdio: 'inherit',
118
- });
119
- }
120
- catch {
121
- // Detach is normal exit
122
- }
123
- },
124
- };
125
- }
126
- else if (session.type === 'multipass') {
127
- const vmName = session.genbox || session.name;
128
- return {
129
- attach: () => {
130
- try {
131
- (0, child_process_1.execSync)(`multipass exec ${vmName} -- dtach -a ${socketPath}`, {
132
- stdio: 'inherit',
133
- });
134
- }
135
- catch {
136
- // Detach is normal exit
137
- }
138
- },
139
- };
140
- }
141
- return { attach: () => { } };
142
- }, []);
143
- /**
144
- * Send a prompt to a session via daemon API
145
- */
146
- const sendPrompt = (0, react_1.useCallback)(async (session, prompt) => {
147
- if (!session.genbox || session.type !== 'cloud') {
148
- // For local sessions, we'd need a different approach
149
- return false;
150
- }
151
- try {
152
- // Try daemon API first
153
- const escapedPrompt = prompt.replace(/'/g, "'\\''");
154
- await execAsync(`ssh -o ConnectTimeout=5 -o BatchMode=yes genbox-${session.genbox} '
155
- curl -s -X POST "http://127.0.0.1:47191/api/sessions/${session.name}/send" \
156
- -H "Content-Type: application/json" \
157
- -d '"'"'{"prompt": "${escapedPrompt}"}'"'"' 2>/dev/null ||
158
- curl -s -X POST "http://127.0.0.1:47192/api/sessions/${session.name}/send" \
159
- -H "Content-Type: application/json" \
160
- -d '"'"'{"prompt": "${escapedPrompt}"}'"'"' 2>/dev/null
161
- '`, { encoding: 'utf8', timeout: 10000 });
162
- return true;
163
- }
164
- catch {
165
- return false;
166
- }
167
- }, []);
168
- /**
169
- * Kill a session
170
- */
171
- const killSession = (0, react_1.useCallback)(async (session) => {
172
- try {
173
- if (session.type === 'cloud' && session.genbox) {
174
- // Kill via daemon API or remove socket
175
- await execAsync(`ssh -o ConnectTimeout=5 -o BatchMode=yes genbox-${session.genbox} '
176
- curl -s -X POST "http://127.0.0.1:47191/api/sessions/${session.name}/stop" 2>/dev/null ||
177
- curl -s -X POST "http://127.0.0.1:47192/api/sessions/${session.name}/stop" 2>/dev/null ||
178
- rm -f /home/dev/.genbox/sockets/${session.name}.sock
179
- '`, { encoding: 'utf8', timeout: 10000 });
180
- }
181
- else if (session.type === 'native') {
182
- const socketPath = path.join(getDtachSocketDir(), `${session.name}.sock`);
183
- await execAsync(`rm -f "${socketPath}"`, { encoding: 'utf8' });
184
- }
185
- else if (session.type === 'docker') {
186
- const containerName = session.genbox || session.name;
187
- await execAsync(`docker exec ${containerName} rm -f /home/dev/.genbox/sockets/${session.name}.sock`, { encoding: 'utf8' });
188
- }
189
- else if (session.type === 'multipass') {
190
- const vmName = session.genbox || session.name;
191
- await execAsync(`multipass exec ${vmName} -- rm -f /home/dev/.genbox/sockets/${session.name}.sock`, { encoding: 'utf8' });
192
- }
193
- return true;
194
- }
195
- catch {
196
- return false;
197
- }
198
- }, []);
199
- /**
200
- * Show kill confirmation modal
201
- */
202
- const confirmKillSession = (0, react_1.useCallback)((session, onConfirm) => {
203
- setModal({
204
- type: 'confirm',
205
- title: 'Kill Session',
206
- message: `Are you sure you want to kill "${session.name}"?`,
207
- confirmLabel: 'Kill',
208
- cancelLabel: 'Cancel',
209
- onConfirm: () => {
210
- killSession(session).then(() => {
211
- onConfirm();
212
- });
213
- setModal(null);
214
- },
215
- onCancel: () => setModal(null),
216
- });
217
- }, [setModal, killSession]);
218
- return {
219
- attachToSession,
220
- sendPrompt,
221
- killSession,
222
- confirmKillSession,
223
- };
224
- }