@mod-computer/cli 0.2.4 → 0.2.5
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/package.json +3 -3
- package/dist/app.js +0 -227
- package/dist/cli.bundle.js.map +0 -7
- package/dist/cli.js +0 -132
- package/dist/commands/add.js +0 -245
- package/dist/commands/agents-run.js +0 -71
- package/dist/commands/auth.js +0 -259
- package/dist/commands/branch.js +0 -1411
- package/dist/commands/claude-sync.js +0 -772
- package/dist/commands/comment.js +0 -568
- package/dist/commands/diff.js +0 -182
- package/dist/commands/index.js +0 -73
- package/dist/commands/init.js +0 -597
- package/dist/commands/ls.js +0 -135
- package/dist/commands/members.js +0 -687
- package/dist/commands/mv.js +0 -282
- package/dist/commands/recover.js +0 -207
- package/dist/commands/rm.js +0 -257
- package/dist/commands/spec.js +0 -386
- package/dist/commands/status.js +0 -296
- package/dist/commands/sync.js +0 -119
- package/dist/commands/trace.js +0 -1752
- package/dist/commands/workspace.js +0 -447
- package/dist/components/conflict-resolution-ui.js +0 -120
- package/dist/components/messages.js +0 -5
- package/dist/components/thread.js +0 -8
- package/dist/config/features.js +0 -83
- package/dist/containers/branches-container.js +0 -140
- package/dist/containers/directory-container.js +0 -92
- package/dist/containers/thread-container.js +0 -214
- package/dist/containers/threads-container.js +0 -27
- package/dist/containers/workspaces-container.js +0 -27
- package/dist/daemon/conflict-resolution.js +0 -172
- package/dist/daemon/content-hash.js +0 -31
- package/dist/daemon/file-sync.js +0 -985
- package/dist/daemon/index.js +0 -203
- package/dist/daemon/mime-types.js +0 -166
- package/dist/daemon/offline-queue.js +0 -211
- package/dist/daemon/path-utils.js +0 -64
- package/dist/daemon/share-policy.js +0 -83
- package/dist/daemon/wasm-errors.js +0 -189
- package/dist/daemon/worker.js +0 -557
- package/dist/daemon-worker.js +0 -258
- package/dist/errors/workspace-errors.js +0 -48
- package/dist/lib/auth-server.js +0 -216
- package/dist/lib/browser.js +0 -35
- package/dist/lib/diff.js +0 -284
- package/dist/lib/formatters.js +0 -204
- package/dist/lib/git.js +0 -137
- package/dist/lib/local-fs.js +0 -201
- package/dist/lib/prompts.js +0 -56
- package/dist/lib/storage.js +0 -213
- package/dist/lib/trace-formatters.js +0 -314
- package/dist/services/add-service.js +0 -554
- package/dist/services/add-validation.js +0 -124
- package/dist/services/automatic-file-tracker.js +0 -303
- package/dist/services/cli-orchestrator.js +0 -227
- package/dist/services/feature-flags.js +0 -187
- package/dist/services/file-import-service.js +0 -283
- package/dist/services/file-transformation-service.js +0 -218
- package/dist/services/logger.js +0 -44
- package/dist/services/mod-config.js +0 -67
- package/dist/services/modignore-service.js +0 -328
- package/dist/services/sync-daemon.js +0 -244
- package/dist/services/thread-notification-service.js +0 -50
- package/dist/services/thread-service.js +0 -147
- package/dist/stores/use-directory-store.js +0 -96
- package/dist/stores/use-threads-store.js +0 -46
- package/dist/stores/use-workspaces-store.js +0 -54
- package/dist/types/add-types.js +0 -99
- package/dist/types/config.js +0 -16
- package/dist/types/index.js +0 -2
- package/dist/types/workspace-connection.js +0 -53
- package/dist/types.js +0 -1
package/dist/daemon-worker.js
DELETED
|
@@ -1,258 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import * as fs from 'fs/promises';
|
|
3
|
-
import * as path from 'path';
|
|
4
|
-
import { fileURLToPath } from 'url';
|
|
5
|
-
import chokidar from 'chokidar';
|
|
6
|
-
import { AutomaticFileTracker } from './services/automatic-file-tracker.js';
|
|
7
|
-
import { createModWorkspace } from '@mod/mod-core';
|
|
8
|
-
import { repo as getRepo } from '@mod/mod-core/repos/repo.node';
|
|
9
|
-
import { readModConfig } from './services/mod-config.js';
|
|
10
|
-
// TODO: Replace with new SyncDiagnostics when implemented
|
|
11
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
-
const __dirname = path.dirname(__filename);
|
|
13
|
-
class DaemonWorker {
|
|
14
|
-
constructor(options) {
|
|
15
|
-
this.isShuttingDown = false;
|
|
16
|
-
this.options = options;
|
|
17
|
-
this.stateFilePath = path.join(options.workingDir, '.mod', '.cache', 'sync-daemon.json');
|
|
18
|
-
}
|
|
19
|
-
async start() {
|
|
20
|
-
try {
|
|
21
|
-
process.on('SIGTERM', () => this.gracefulShutdown());
|
|
22
|
-
process.on('SIGINT', () => this.gracefulShutdown());
|
|
23
|
-
process.on('uncaughtException', (error) => this.handleError(error));
|
|
24
|
-
process.on('unhandledRejection', (error) => this.handleError(error));
|
|
25
|
-
await this.updateState({
|
|
26
|
-
status: 'running',
|
|
27
|
-
lastActivity: new Date().toISOString(),
|
|
28
|
-
watchedFiles: 0
|
|
29
|
-
});
|
|
30
|
-
if (this.options.verbose) {
|
|
31
|
-
console.log(`🚀 Daemon worker starting...`);
|
|
32
|
-
console.log(`📁 Working directory: ${this.options.workingDir}`);
|
|
33
|
-
console.log(`🔗 Workspace ID: ${this.options.workspaceId}`);
|
|
34
|
-
console.log(`🌿 Active branch: ${this.options.activeBranchId}`);
|
|
35
|
-
}
|
|
36
|
-
// Initialize repo and workspace
|
|
37
|
-
const repo = await this.initializeRepo();
|
|
38
|
-
this.repo = repo;
|
|
39
|
-
const modWorkspace = createModWorkspace(repo);
|
|
40
|
-
const workspaceHandles = await modWorkspace.listWorkspaces();
|
|
41
|
-
this.workspaceHandle = workspaceHandles.find(wh => wh.id === this.options.workspaceId);
|
|
42
|
-
if (!this.workspaceHandle) {
|
|
43
|
-
throw new Error(`Workspace ${this.options.workspaceId} not found`);
|
|
44
|
-
}
|
|
45
|
-
// Set active branch
|
|
46
|
-
if (this.options.activeBranchId) {
|
|
47
|
-
try {
|
|
48
|
-
await this.workspaceHandle.branch.switchActive(this.options.activeBranchId);
|
|
49
|
-
}
|
|
50
|
-
catch (error) {
|
|
51
|
-
console.warn(`⚠️ Failed to set active branch: ${error}`);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
await this.setupConfigWatcher();
|
|
55
|
-
this.tracker = new AutomaticFileTracker(repo);
|
|
56
|
-
await this.tracker.enableAutoTracking({
|
|
57
|
-
workspaceId: this.options.workspaceId,
|
|
58
|
-
workspaceHandle: this.workspaceHandle,
|
|
59
|
-
watchDirectory: this.options.workingDir,
|
|
60
|
-
debounceMs: 500,
|
|
61
|
-
verbose: this.options.verbose || false,
|
|
62
|
-
maxWatchedFiles: 2000,
|
|
63
|
-
preFilterEnabled: true,
|
|
64
|
-
comprehensiveMode: true,
|
|
65
|
-
resourceMonitoring: true
|
|
66
|
-
});
|
|
67
|
-
const status = this.tracker.getTrackingStatus();
|
|
68
|
-
await this.updateState({
|
|
69
|
-
watchedFiles: status.watchedFiles,
|
|
70
|
-
lastActivity: new Date().toISOString()
|
|
71
|
-
});
|
|
72
|
-
if (this.options.verbose) {
|
|
73
|
-
console.log(`✅ Daemon worker running (PID: ${process.pid})`);
|
|
74
|
-
console.log(`📊 Watching ${status.watchedFiles} files`);
|
|
75
|
-
}
|
|
76
|
-
await this.keepAlive();
|
|
77
|
-
}
|
|
78
|
-
catch (error) {
|
|
79
|
-
await this.handleError(error);
|
|
80
|
-
process.exit(1);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
async gracefulShutdown() {
|
|
84
|
-
if (this.isShuttingDown)
|
|
85
|
-
return;
|
|
86
|
-
this.isShuttingDown = true;
|
|
87
|
-
console.log('\n🛑 Daemon worker shutting down...');
|
|
88
|
-
try {
|
|
89
|
-
await this.updateState({
|
|
90
|
-
status: 'stopping',
|
|
91
|
-
lastActivity: new Date().toISOString()
|
|
92
|
-
});
|
|
93
|
-
if (this.tracker) {
|
|
94
|
-
await this.tracker.disableAutoTracking();
|
|
95
|
-
}
|
|
96
|
-
if (this.configWatcher) {
|
|
97
|
-
await this.configWatcher.close();
|
|
98
|
-
}
|
|
99
|
-
await this.updateState({
|
|
100
|
-
status: 'stopped',
|
|
101
|
-
lastActivity: new Date().toISOString()
|
|
102
|
-
});
|
|
103
|
-
console.log('✅ Daemon worker stopped gracefully');
|
|
104
|
-
process.exit(0);
|
|
105
|
-
}
|
|
106
|
-
catch (error) {
|
|
107
|
-
console.error('Error during graceful shutdown:', error);
|
|
108
|
-
process.exit(1);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
async handleError(error) {
|
|
112
|
-
console.error('💥 Daemon worker error:', error);
|
|
113
|
-
try {
|
|
114
|
-
await this.updateState({
|
|
115
|
-
status: 'crashed',
|
|
116
|
-
lastError: error.message || 'Unknown error',
|
|
117
|
-
lastActivity: new Date().toISOString()
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
catch (stateError) {
|
|
121
|
-
console.error('Failed to update error state:', stateError);
|
|
122
|
-
}
|
|
123
|
-
// Let the main daemon handle restart logic
|
|
124
|
-
process.exit(1);
|
|
125
|
-
}
|
|
126
|
-
async keepAlive() {
|
|
127
|
-
while (!this.isShuttingDown) {
|
|
128
|
-
try {
|
|
129
|
-
await this.updateState({
|
|
130
|
-
lastActivity: new Date().toISOString()
|
|
131
|
-
});
|
|
132
|
-
// Check if tracking is still active
|
|
133
|
-
if (this.tracker) {
|
|
134
|
-
const status = this.tracker.getTrackingStatus();
|
|
135
|
-
if (status.watchedFiles !== undefined) {
|
|
136
|
-
await this.updateState({ watchedFiles: status.watchedFiles });
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
await new Promise(resolve => setTimeout(resolve, 10000)); // 10 second intervals
|
|
140
|
-
}
|
|
141
|
-
catch (error) {
|
|
142
|
-
await this.handleError(error);
|
|
143
|
-
break;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
async updateState(updates) {
|
|
148
|
-
try {
|
|
149
|
-
let currentState = {};
|
|
150
|
-
try {
|
|
151
|
-
const data = await fs.readFile(this.stateFilePath, 'utf8');
|
|
152
|
-
currentState = JSON.parse(data);
|
|
153
|
-
}
|
|
154
|
-
catch { /* State file doesn't exist yet */ }
|
|
155
|
-
const newState = { ...currentState, ...updates, pid: process.pid };
|
|
156
|
-
await fs.writeFile(this.stateFilePath, JSON.stringify(newState, null, 2), 'utf8');
|
|
157
|
-
}
|
|
158
|
-
catch (error) {
|
|
159
|
-
console.error('Failed to update daemon state:', error);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
async setupConfigWatcher() {
|
|
163
|
-
const configPath = path.join(this.options.workingDir, '.mod', 'config.json');
|
|
164
|
-
this.configWatcher = chokidar.watch(configPath, {
|
|
165
|
-
persistent: true,
|
|
166
|
-
ignoreInitial: true
|
|
167
|
-
});
|
|
168
|
-
this.configWatcher.on('change', async () => {
|
|
169
|
-
try {
|
|
170
|
-
await this.handleConfigChange();
|
|
171
|
-
}
|
|
172
|
-
catch (error) {
|
|
173
|
-
console.error('Error handling config change:', error);
|
|
174
|
-
}
|
|
175
|
-
});
|
|
176
|
-
if (this.options.verbose) {
|
|
177
|
-
console.log(`🔍 Watching config file: ${configPath}`);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
async handleConfigChange() {
|
|
181
|
-
try {
|
|
182
|
-
// Read the updated config
|
|
183
|
-
const config = readModConfig();
|
|
184
|
-
if (!config?.activeBranchId) {
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
// Check if the branch has actually changed
|
|
188
|
-
if (config.activeBranchId === this.options.activeBranchId) {
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
if (this.options.verbose) {
|
|
192
|
-
console.log(`🔄 Branch switch detected: ${this.options.activeBranchId} → ${config.activeBranchId}`);
|
|
193
|
-
}
|
|
194
|
-
if (this.workspaceHandle) {
|
|
195
|
-
try {
|
|
196
|
-
await this.workspaceHandle.branch.switchActive(config.activeBranchId);
|
|
197
|
-
this.options.activeBranchId = config.activeBranchId;
|
|
198
|
-
await this.updateState({
|
|
199
|
-
activeBranchId: config.activeBranchId,
|
|
200
|
-
lastActivity: new Date().toISOString()
|
|
201
|
-
});
|
|
202
|
-
if (this.options.verbose) {
|
|
203
|
-
console.log(`✅ Switched to branch: ${config.activeBranchId}`);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
catch (error) {
|
|
207
|
-
console.error(`❌ Failed to switch to branch ${config.activeBranchId}:`, error);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
catch (error) {
|
|
212
|
-
console.error('Error reading config during branch switch:', error);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
async initializeRepo() {
|
|
216
|
-
// Use the same repo initialization as the main CLI
|
|
217
|
-
return await getRepo();
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
221
|
-
const args = process.argv.slice(2);
|
|
222
|
-
const options = {
|
|
223
|
-
workspaceId: '',
|
|
224
|
-
activeBranchId: 'main',
|
|
225
|
-
workingDir: process.cwd(),
|
|
226
|
-
verbose: false
|
|
227
|
-
};
|
|
228
|
-
// Parse command line arguments
|
|
229
|
-
for (let i = 0; i < args.length; i += 2) {
|
|
230
|
-
const key = args[i];
|
|
231
|
-
const value = args[i + 1];
|
|
232
|
-
switch (key) {
|
|
233
|
-
case '--workspace-id':
|
|
234
|
-
options.workspaceId = value;
|
|
235
|
-
break;
|
|
236
|
-
case '--active-branch':
|
|
237
|
-
options.activeBranchId = value;
|
|
238
|
-
break;
|
|
239
|
-
case '--working-dir':
|
|
240
|
-
options.workingDir = value;
|
|
241
|
-
break;
|
|
242
|
-
case '--verbose':
|
|
243
|
-
options.verbose = true;
|
|
244
|
-
i--; // No value for this flag
|
|
245
|
-
break;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
if (!options.workspaceId) {
|
|
249
|
-
console.error('❌ Workspace ID is required');
|
|
250
|
-
process.exit(1);
|
|
251
|
-
}
|
|
252
|
-
const worker = new DaemonWorker(options);
|
|
253
|
-
worker.start().catch((error) => {
|
|
254
|
-
console.error('❌ Failed to start daemon worker:', error);
|
|
255
|
-
process.exit(1);
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
export { DaemonWorker };
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
// glassware[type="implementation", id="impl-cli-ws-errors--396f8074", requirements="requirement-cli-ws-error-connection--b7589ae2,requirement-cli-ws-error-storage--88e831ba,requirement-cli-ws-error-validation--192a0457"]
|
|
2
|
-
// spec: packages/mod-cli/specs/workspaces.md
|
|
3
|
-
/**
|
|
4
|
-
* Error thrown when workspace connection operations fail
|
|
5
|
-
*/
|
|
6
|
-
// glassware[type="implementation", id="impl-cli-ws-error-connection--8c8703d4", requirements="requirement-cli-ws-error-connection--b7589ae2"]
|
|
7
|
-
export class WorkspaceConnectionError extends Error {
|
|
8
|
-
constructor(path, reason) {
|
|
9
|
-
super(`Workspace connection error at ${path}: ${reason}`);
|
|
10
|
-
this.name = 'WorkspaceConnectionError';
|
|
11
|
-
this.path = path;
|
|
12
|
-
this.reason = reason;
|
|
13
|
-
if (Error.captureStackTrace) {
|
|
14
|
-
Error.captureStackTrace(this, WorkspaceConnectionError);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Error thrown when workspace storage operations fail
|
|
20
|
-
*/
|
|
21
|
-
// glassware[type="implementation", id="impl-cli-ws-error-storage--3aae8301", requirements="requirement-cli-ws-error-storage--88e831ba"]
|
|
22
|
-
export class WorkspaceStorageError extends Error {
|
|
23
|
-
constructor(operation, filePath, cause) {
|
|
24
|
-
super(`Storage ${operation} failed for ${filePath}${cause ? `: ${cause.message}` : ''}`);
|
|
25
|
-
this.name = 'WorkspaceStorageError';
|
|
26
|
-
this.operation = operation;
|
|
27
|
-
this.filePath = filePath;
|
|
28
|
-
this.cause = cause;
|
|
29
|
-
if (Error.captureStackTrace) {
|
|
30
|
-
Error.captureStackTrace(this, WorkspaceStorageError);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Error thrown when workspace connection validation fails
|
|
36
|
-
*/
|
|
37
|
-
// glassware[type="implementation", id="impl-cli-ws-error-validation--36675fe8", requirements="requirement-cli-ws-error-validation--192a0457"]
|
|
38
|
-
export class WorkspaceValidationError extends Error {
|
|
39
|
-
constructor(errors) {
|
|
40
|
-
const message = `Workspace validation failed: ${errors.map(e => e.message).join(', ')}`;
|
|
41
|
-
super(message);
|
|
42
|
-
this.name = 'WorkspaceValidationError';
|
|
43
|
-
this.errors = errors;
|
|
44
|
-
if (Error.captureStackTrace) {
|
|
45
|
-
Error.captureStackTrace(this, WorkspaceValidationError);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
package/dist/lib/auth-server.js
DELETED
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
// glassware[type="implementation", id="impl-auth-server--59aa04a6", specifications="specification-spec-localhost-server--6f8cb512,specification-spec-receive-callback--09de208c,specification-spec-server-timeout--163a7a48"]
|
|
2
|
-
import http from 'http';
|
|
3
|
-
import { URL } from 'url';
|
|
4
|
-
const DEFAULT_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
|
|
5
|
-
/**
|
|
6
|
-
* Start a localhost HTTP server to receive OAuth callback.
|
|
7
|
-
* Returns the port number and a promise that resolves with auth result.
|
|
8
|
-
*/
|
|
9
|
-
export async function startAuthServer(options = {}) {
|
|
10
|
-
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
11
|
-
let resolveAuth;
|
|
12
|
-
let rejectAuth;
|
|
13
|
-
const resultPromise = new Promise((resolve, reject) => {
|
|
14
|
-
resolveAuth = resolve;
|
|
15
|
-
rejectAuth = reject;
|
|
16
|
-
});
|
|
17
|
-
const server = http.createServer((req, res) => {
|
|
18
|
-
const url = new URL(req.url || '/', `http://localhost`);
|
|
19
|
-
if (url.pathname === '/callback') {
|
|
20
|
-
const token = url.searchParams.get('token');
|
|
21
|
-
const email = url.searchParams.get('email');
|
|
22
|
-
const name = url.searchParams.get('name');
|
|
23
|
-
const googleId = url.searchParams.get('googleId');
|
|
24
|
-
if (token && email && googleId) {
|
|
25
|
-
// Send success page to browser
|
|
26
|
-
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
27
|
-
res.end(getSuccessPage(name || email));
|
|
28
|
-
// Resolve with auth result
|
|
29
|
-
resolveAuth({
|
|
30
|
-
googleIdToken: token,
|
|
31
|
-
googleId,
|
|
32
|
-
email,
|
|
33
|
-
name: name || email.split('@')[0],
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
// Missing parameters
|
|
38
|
-
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
39
|
-
res.end(getErrorPage('Missing authentication parameters'));
|
|
40
|
-
rejectAuth(new Error('Missing authentication parameters in callback'));
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
45
|
-
res.end('Not found');
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
// Wait for server to start listening
|
|
49
|
-
const port = await new Promise((resolve, reject) => {
|
|
50
|
-
server.on('error', reject);
|
|
51
|
-
server.listen(0, '127.0.0.1', () => {
|
|
52
|
-
const address = server.address();
|
|
53
|
-
const port = typeof address === 'object' && address ? address.port : 0;
|
|
54
|
-
resolve(port);
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
// Set timeout
|
|
58
|
-
const timeoutId = setTimeout(() => {
|
|
59
|
-
server.close();
|
|
60
|
-
rejectAuth(new Error('Authentication timed out after 5 minutes'));
|
|
61
|
-
}, timeoutMs);
|
|
62
|
-
// Close server when auth completes
|
|
63
|
-
resultPromise.finally(() => {
|
|
64
|
-
clearTimeout(timeoutId);
|
|
65
|
-
server.close();
|
|
66
|
-
});
|
|
67
|
-
return {
|
|
68
|
-
port,
|
|
69
|
-
result: resultPromise,
|
|
70
|
-
close: () => {
|
|
71
|
-
clearTimeout(timeoutId);
|
|
72
|
-
server.close();
|
|
73
|
-
rejectAuth(new Error('Authentication cancelled'));
|
|
74
|
-
},
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
function getSuccessPage(name) {
|
|
78
|
-
const modLogo = `<svg width="48" height="54" viewBox="0 0 33 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
79
|
-
<path opacity="0.8" d="M16.4287 5.04502C16.4287 2.76982 18.8623 1.32269 20.8613 2.40918L31.2899 8.07724C32.2559 8.60226 32.8573 9.61363 32.8573 10.7131V21.9875C32.8573 24.2715 30.4066 25.7178 28.4072 24.6138L17.9786 18.8558C17.0224 18.3278 16.4287 17.3218 16.4287 16.2295V5.04502Z" fill="#FF2B00"/>
|
|
80
|
-
<path opacity="0.7" d="M8.14282 9.43857C8.14282 7.16338 10.5764 5.71625 12.5754 6.80274L23.004 12.4708C23.97 12.9958 24.5714 14.0072 24.5714 15.1066V26.3811C24.5714 28.6651 22.1208 30.1113 20.1213 29.0074L9.69275 23.2493C8.73652 22.7214 8.14282 21.7154 8.14282 20.6231V9.43857Z" fill="white"/>
|
|
81
|
-
<path opacity="0.8" d="M0 13.9742C0 11.699 2.4336 10.2519 4.43261 11.3384L14.8612 17.0064C15.8271 17.5315 16.4286 18.5428 16.4286 19.6423V30.9167C16.4286 33.2007 13.9779 34.647 11.9785 33.543L1.54993 27.785C0.593696 27.257 0 26.251 0 25.1587V13.9742Z" fill="#3671F1"/>
|
|
82
|
-
</svg>`;
|
|
83
|
-
return `<!DOCTYPE html>
|
|
84
|
-
<html>
|
|
85
|
-
<head>
|
|
86
|
-
<title>Signed in to Mod</title>
|
|
87
|
-
<style>
|
|
88
|
-
* { box-sizing: border-box; }
|
|
89
|
-
body {
|
|
90
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
91
|
-
display: flex;
|
|
92
|
-
justify-content: center;
|
|
93
|
-
align-items: center;
|
|
94
|
-
min-height: 100vh;
|
|
95
|
-
margin: 0;
|
|
96
|
-
padding: 1rem;
|
|
97
|
-
background: #09090b;
|
|
98
|
-
color: #fafafa;
|
|
99
|
-
}
|
|
100
|
-
.card {
|
|
101
|
-
width: 100%;
|
|
102
|
-
max-width: 24rem;
|
|
103
|
-
background: #18181b;
|
|
104
|
-
border: 1px solid #27272a;
|
|
105
|
-
border-radius: 0.5rem;
|
|
106
|
-
padding: 1.5rem;
|
|
107
|
-
box-shadow: 0 1px 3px rgba(0,0,0,0.3);
|
|
108
|
-
}
|
|
109
|
-
.logo-container {
|
|
110
|
-
display: flex;
|
|
111
|
-
flex-direction: column;
|
|
112
|
-
align-items: center;
|
|
113
|
-
}
|
|
114
|
-
.logo {
|
|
115
|
-
margin-bottom: 1rem;
|
|
116
|
-
}
|
|
117
|
-
h1 {
|
|
118
|
-
font-size: 1.125rem;
|
|
119
|
-
font-weight: 600;
|
|
120
|
-
margin: 0 0 0.25rem 0;
|
|
121
|
-
text-align: center;
|
|
122
|
-
}
|
|
123
|
-
.subtitle {
|
|
124
|
-
color: #a1a1aa;
|
|
125
|
-
font-size: 0.875rem;
|
|
126
|
-
text-align: center;
|
|
127
|
-
margin: 0;
|
|
128
|
-
}
|
|
129
|
-
</style>
|
|
130
|
-
</head>
|
|
131
|
-
<body>
|
|
132
|
-
<div class="card">
|
|
133
|
-
<div class="logo-container">
|
|
134
|
-
<div class="logo">${modLogo}</div>
|
|
135
|
-
<h1>Welcome, ${escapeHtml(name)}!</h1>
|
|
136
|
-
<p class="subtitle">You can close this window and return to your terminal.</p>
|
|
137
|
-
</div>
|
|
138
|
-
</div>
|
|
139
|
-
</body>
|
|
140
|
-
</html>`;
|
|
141
|
-
}
|
|
142
|
-
function getErrorPage(message) {
|
|
143
|
-
const modLogo = `<svg width="48" height="54" viewBox="0 0 33 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
144
|
-
<path opacity="0.8" d="M16.4287 5.04502C16.4287 2.76982 18.8623 1.32269 20.8613 2.40918L31.2899 8.07724C32.2559 8.60226 32.8573 9.61363 32.8573 10.7131V21.9875C32.8573 24.2715 30.4066 25.7178 28.4072 24.6138L17.9786 18.8558C17.0224 18.3278 16.4287 17.3218 16.4287 16.2295V5.04502Z" fill="#FF2B00"/>
|
|
145
|
-
<path opacity="0.7" d="M8.14282 9.43857C8.14282 7.16338 10.5764 5.71625 12.5754 6.80274L23.004 12.4708C23.97 12.9958 24.5714 14.0072 24.5714 15.1066V26.3811C24.5714 28.6651 22.1208 30.1113 20.1213 29.0074L9.69275 23.2493C8.73652 22.7214 8.14282 21.7154 8.14282 20.6231V9.43857Z" fill="white"/>
|
|
146
|
-
<path opacity="0.8" d="M0 13.9742C0 11.699 2.4336 10.2519 4.43261 11.3384L14.8612 17.0064C15.8271 17.5315 16.4286 18.5428 16.4286 19.6423V30.9167C16.4286 33.2007 13.9779 34.647 11.9785 33.543L1.54993 27.785C0.593696 27.257 0 26.251 0 25.1587V13.9742Z" fill="#3671F1"/>
|
|
147
|
-
</svg>`;
|
|
148
|
-
return `<!DOCTYPE html>
|
|
149
|
-
<html>
|
|
150
|
-
<head>
|
|
151
|
-
<title>Authentication Error</title>
|
|
152
|
-
<style>
|
|
153
|
-
* { box-sizing: border-box; }
|
|
154
|
-
body {
|
|
155
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
156
|
-
display: flex;
|
|
157
|
-
justify-content: center;
|
|
158
|
-
align-items: center;
|
|
159
|
-
min-height: 100vh;
|
|
160
|
-
margin: 0;
|
|
161
|
-
padding: 1rem;
|
|
162
|
-
background: #09090b;
|
|
163
|
-
color: #fafafa;
|
|
164
|
-
}
|
|
165
|
-
.card {
|
|
166
|
-
width: 100%;
|
|
167
|
-
max-width: 24rem;
|
|
168
|
-
background: #18181b;
|
|
169
|
-
border: 1px solid #27272a;
|
|
170
|
-
border-radius: 0.5rem;
|
|
171
|
-
padding: 1.5rem;
|
|
172
|
-
box-shadow: 0 1px 3px rgba(0,0,0,0.3);
|
|
173
|
-
}
|
|
174
|
-
.logo-container {
|
|
175
|
-
display: flex;
|
|
176
|
-
flex-direction: column;
|
|
177
|
-
align-items: center;
|
|
178
|
-
}
|
|
179
|
-
.logo {
|
|
180
|
-
margin-bottom: 1rem;
|
|
181
|
-
}
|
|
182
|
-
h1 {
|
|
183
|
-
font-size: 1.125rem;
|
|
184
|
-
font-weight: 600;
|
|
185
|
-
margin: 0 0 0.5rem 0;
|
|
186
|
-
color: #ef4444;
|
|
187
|
-
text-align: center;
|
|
188
|
-
}
|
|
189
|
-
.message {
|
|
190
|
-
color: #a1a1aa;
|
|
191
|
-
font-size: 0.875rem;
|
|
192
|
-
text-align: center;
|
|
193
|
-
margin: 0 0 0.25rem 0;
|
|
194
|
-
}
|
|
195
|
-
</style>
|
|
196
|
-
</head>
|
|
197
|
-
<body>
|
|
198
|
-
<div class="card">
|
|
199
|
-
<div class="logo-container">
|
|
200
|
-
<div class="logo">${modLogo}</div>
|
|
201
|
-
<h1>Authentication Error</h1>
|
|
202
|
-
<p class="message">${escapeHtml(message)}</p>
|
|
203
|
-
<p class="message">Please try again from your terminal.</p>
|
|
204
|
-
</div>
|
|
205
|
-
</div>
|
|
206
|
-
</body>
|
|
207
|
-
</html>`;
|
|
208
|
-
}
|
|
209
|
-
function escapeHtml(str) {
|
|
210
|
-
return str
|
|
211
|
-
.replace(/&/g, '&')
|
|
212
|
-
.replace(/</g, '<')
|
|
213
|
-
.replace(/>/g, '>')
|
|
214
|
-
.replace(/"/g, '"')
|
|
215
|
-
.replace(/'/g, ''');
|
|
216
|
-
}
|
package/dist/lib/browser.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
// glassware[type="implementation", id="impl-browser-opener--15759c87", specifications="specification-spec-open-browser--397b6a28,specification-spec-manual-url--b37b2760"]
|
|
2
|
-
import { exec } from 'child_process';
|
|
3
|
-
import { platform } from 'os';
|
|
4
|
-
/**
|
|
5
|
-
* Open a URL in the default browser.
|
|
6
|
-
* Returns true if successful, false if browser couldn't be opened.
|
|
7
|
-
*/
|
|
8
|
-
export async function openBrowser(url) {
|
|
9
|
-
const command = getBrowserCommand(url);
|
|
10
|
-
return new Promise((resolve) => {
|
|
11
|
-
exec(command, (error) => {
|
|
12
|
-
if (error) {
|
|
13
|
-
resolve(false);
|
|
14
|
-
}
|
|
15
|
-
else {
|
|
16
|
-
resolve(true);
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Get the platform-specific command to open a URL.
|
|
23
|
-
*/
|
|
24
|
-
function getBrowserCommand(url) {
|
|
25
|
-
const escapedUrl = url.replace(/"/g, '\\"');
|
|
26
|
-
switch (platform()) {
|
|
27
|
-
case 'darwin':
|
|
28
|
-
return `open "${escapedUrl}"`;
|
|
29
|
-
case 'win32':
|
|
30
|
-
return `start "" "${escapedUrl}"`;
|
|
31
|
-
default:
|
|
32
|
-
// Linux and others - try xdg-open
|
|
33
|
-
return `xdg-open "${escapedUrl}"`;
|
|
34
|
-
}
|
|
35
|
-
}
|