spck 0.3.1
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/.oxlintrc.json +49 -0
- package/LICENSE +21 -0
- package/README.md +631 -0
- package/bin/cli.js +20 -0
- package/bin/validate-cwd.js +41 -0
- package/dist/config/__tests__/config.test.d.ts +2 -0
- package/dist/config/__tests__/config.test.js +262 -0
- package/dist/config/__tests__/credentials.test.d.ts +2 -0
- package/dist/config/__tests__/credentials.test.js +360 -0
- package/dist/config/config.d.ts +33 -0
- package/dist/config/config.js +185 -0
- package/dist/config/credentials.d.ts +75 -0
- package/dist/config/credentials.js +259 -0
- package/dist/config/server-selection.d.ts +40 -0
- package/dist/config/server-selection.js +130 -0
- package/dist/connection/__tests__/firebase-auth.test.d.ts +2 -0
- package/dist/connection/__tests__/firebase-auth.test.js +96 -0
- package/dist/connection/__tests__/hmac.test.d.ts +2 -0
- package/dist/connection/__tests__/hmac.test.js +372 -0
- package/dist/connection/auth.d.ts +13 -0
- package/dist/connection/auth.js +91 -0
- package/dist/connection/firebase-auth.d.ts +40 -0
- package/dist/connection/firebase-auth.js +429 -0
- package/dist/connection/hmac.d.ts +24 -0
- package/dist/connection/hmac.js +109 -0
- package/dist/i18n/index.d.ts +25 -0
- package/dist/i18n/index.js +101 -0
- package/dist/i18n/locales/en.json +313 -0
- package/dist/i18n/locales/es.json +302 -0
- package/dist/i18n/locales/fr.json +302 -0
- package/dist/i18n/locales/id.json +302 -0
- package/dist/i18n/locales/ja.json +302 -0
- package/dist/i18n/locales/ko.json +302 -0
- package/dist/i18n/locales/locales/en.json +309 -0
- package/dist/i18n/locales/locales/es.json +302 -0
- package/dist/i18n/locales/locales/fr.json +302 -0
- package/dist/i18n/locales/locales/id.json +302 -0
- package/dist/i18n/locales/locales/ja.json +302 -0
- package/dist/i18n/locales/locales/ko.json +302 -0
- package/dist/i18n/locales/locales/pt.json +302 -0
- package/dist/i18n/locales/locales/zh-Hans.json +302 -0
- package/dist/i18n/locales/pt.json +302 -0
- package/dist/i18n/locales/zh-Hans.json +302 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +493 -0
- package/dist/proxy/ProxyClient.d.ts +125 -0
- package/dist/proxy/ProxyClient.js +781 -0
- package/dist/proxy/ProxySocketWrapper.d.ts +43 -0
- package/dist/proxy/ProxySocketWrapper.js +98 -0
- package/dist/proxy/__tests__/ProxyClient.test.d.ts +2 -0
- package/dist/proxy/__tests__/ProxyClient.test.js +445 -0
- package/dist/proxy/__tests__/ProxySocketWrapper.test.d.ts +2 -0
- package/dist/proxy/__tests__/ProxySocketWrapper.test.js +190 -0
- package/dist/proxy/__tests__/handshake-validation.test.d.ts +2 -0
- package/dist/proxy/__tests__/handshake-validation.test.js +282 -0
- package/dist/proxy/__tests__/token-refresh-race.test.d.ts +14 -0
- package/dist/proxy/__tests__/token-refresh-race.test.js +173 -0
- package/dist/proxy/chunking.d.ts +53 -0
- package/dist/proxy/chunking.js +127 -0
- package/dist/proxy/handshake-validation.d.ts +21 -0
- package/dist/proxy/handshake-validation.js +49 -0
- package/dist/rpc/__tests__/router.test.d.ts +2 -0
- package/dist/rpc/__tests__/router.test.js +262 -0
- package/dist/rpc/router.d.ts +37 -0
- package/dist/rpc/router.js +132 -0
- package/dist/services/BrowserProxyService.d.ts +13 -0
- package/dist/services/BrowserProxyService.js +139 -0
- package/dist/services/FilesystemService.d.ts +99 -0
- package/dist/services/FilesystemService.js +742 -0
- package/dist/services/GitService.d.ts +243 -0
- package/dist/services/GitService.js +1439 -0
- package/dist/services/SearchService.d.ts +93 -0
- package/dist/services/SearchService.js +670 -0
- package/dist/services/TerminalService.d.ts +62 -0
- package/dist/services/TerminalService.js +337 -0
- package/dist/services/__tests__/BrowserProxyService.test.d.ts +2 -0
- package/dist/services/__tests__/BrowserProxyService.test.js +145 -0
- package/dist/services/__tests__/FilesystemService.test.d.ts +2 -0
- package/dist/services/__tests__/FilesystemService.test.js +609 -0
- package/dist/services/__tests__/GitService.test.d.ts +2 -0
- package/dist/services/__tests__/GitService.test.js +953 -0
- package/dist/services/__tests__/SearchService.test.d.ts +2 -0
- package/dist/services/__tests__/SearchService.test.js +384 -0
- package/dist/services/__tests__/TerminalService.test.d.ts +2 -0
- package/dist/services/__tests__/TerminalService.test.js +513 -0
- package/dist/setup/wizard.d.ts +10 -0
- package/dist/setup/wizard.js +172 -0
- package/dist/types.d.ts +196 -0
- package/dist/types.js +44 -0
- package/dist/utils/__tests__/gitignore.test.d.ts +2 -0
- package/dist/utils/__tests__/gitignore.test.js +127 -0
- package/dist/utils/gitignore.d.ts +24 -0
- package/dist/utils/gitignore.js +77 -0
- package/dist/utils/logger.d.ts +96 -0
- package/dist/utils/logger.js +456 -0
- package/dist/utils/project-dir.d.ts +51 -0
- package/dist/utils/project-dir.js +191 -0
- package/dist/utils/ripgrep.d.ts +34 -0
- package/dist/utils/ripgrep.js +148 -0
- package/dist/utils/tool-detection.d.ts +17 -0
- package/dist/utils/tool-detection.js +126 -0
- package/dist/watcher/FileWatcher.d.ts +10 -0
- package/dist/watcher/FileWatcher.js +42 -0
- package/package.json +70 -0
- package/src/config/__tests__/config.test.ts +318 -0
- package/src/config/__tests__/credentials.test.ts +494 -0
- package/src/config/config.ts +206 -0
- package/src/config/credentials.ts +302 -0
- package/src/config/server-selection.ts +150 -0
- package/src/connection/__tests__/firebase-auth.test.ts +121 -0
- package/src/connection/__tests__/hmac.test.ts +509 -0
- package/src/connection/auth.ts +140 -0
- package/src/connection/firebase-auth.ts +504 -0
- package/src/connection/hmac.ts +139 -0
- package/src/i18n/index.ts +119 -0
- package/src/i18n/locales/en.json +313 -0
- package/src/i18n/locales/es.json +302 -0
- package/src/i18n/locales/fr.json +302 -0
- package/src/i18n/locales/id.json +302 -0
- package/src/i18n/locales/ja.json +302 -0
- package/src/i18n/locales/ko.json +302 -0
- package/src/i18n/locales/pt.json +302 -0
- package/src/i18n/locales/zh-Hans.json +302 -0
- package/src/index.ts +542 -0
- package/src/proxy/ProxyClient.ts +968 -0
- package/src/proxy/ProxySocketWrapper.ts +113 -0
- package/src/proxy/__tests__/ProxyClient.test.ts +575 -0
- package/src/proxy/__tests__/ProxySocketWrapper.test.ts +251 -0
- package/src/proxy/__tests__/handshake-validation.test.ts +367 -0
- package/src/proxy/chunking.ts +162 -0
- package/src/proxy/handshake-validation.ts +64 -0
- package/src/rpc/__tests__/router.test.ts +400 -0
- package/src/rpc/router.ts +183 -0
- package/src/services/BrowserProxyService.ts +179 -0
- package/src/services/FilesystemService.ts +841 -0
- package/src/services/GitService.ts +1639 -0
- package/src/services/SearchService.ts +809 -0
- package/src/services/TerminalService.ts +413 -0
- package/src/services/__tests__/BrowserProxyService.test.ts +155 -0
- package/src/services/__tests__/FilesystemService.test.ts +1002 -0
- package/src/services/__tests__/GitService.test.ts +1552 -0
- package/src/services/__tests__/SearchService.test.ts +484 -0
- package/src/services/__tests__/TerminalService.test.ts +702 -0
- package/src/setup/wizard.ts +242 -0
- package/src/types/fossil-delta.d.ts +4 -0
- package/src/types.ts +287 -0
- package/src/utils/__tests__/gitignore.test.ts +174 -0
- package/src/utils/gitignore.ts +91 -0
- package/src/utils/logger.ts +578 -0
- package/src/utils/project-dir.ts +218 -0
- package/src/utils/ripgrep.ts +180 -0
- package/src/utils/tool-detection.ts +141 -0
- package/src/watcher/FileWatcher.ts +53 -0
- package/tsconfig.json +24 -0
- package/vitest.config.ts +19 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple, readable logging utility for network operations
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Log a filesystem read operation
|
|
6
|
+
*/
|
|
7
|
+
export declare function logFsRead(method: string, params: {
|
|
8
|
+
path?: string;
|
|
9
|
+
src?: string;
|
|
10
|
+
target?: string;
|
|
11
|
+
oldpath?: string;
|
|
12
|
+
[key: string]: any;
|
|
13
|
+
}, uid: string, success: boolean, error?: any, metadata?: Record<string, any>): void;
|
|
14
|
+
/**
|
|
15
|
+
* Log a filesystem write operation
|
|
16
|
+
*/
|
|
17
|
+
export declare function logFsWrite(method: string, params: {
|
|
18
|
+
path?: string;
|
|
19
|
+
src?: string;
|
|
20
|
+
target?: string;
|
|
21
|
+
oldpath?: string;
|
|
22
|
+
[key: string]: any;
|
|
23
|
+
}, uid: string, success: boolean, error?: any, metadata?: Record<string, any>): void;
|
|
24
|
+
/**
|
|
25
|
+
* Log a git read operation
|
|
26
|
+
*/
|
|
27
|
+
export declare function logGitRead(method: string, params: {
|
|
28
|
+
dir?: string;
|
|
29
|
+
[key: string]: any;
|
|
30
|
+
}, uid: string, success: boolean, error?: any, metadata?: Record<string, any>): void;
|
|
31
|
+
/**
|
|
32
|
+
* Log a git write operation
|
|
33
|
+
*/
|
|
34
|
+
export declare function logGitWrite(method: string, params: {
|
|
35
|
+
dir?: string;
|
|
36
|
+
message?: string;
|
|
37
|
+
filepaths?: string[];
|
|
38
|
+
ref?: string;
|
|
39
|
+
[key: string]: any;
|
|
40
|
+
}, uid: string, success: boolean, error?: any, metadata?: Record<string, any>): void;
|
|
41
|
+
/**
|
|
42
|
+
* Log a terminal read operation
|
|
43
|
+
*/
|
|
44
|
+
export declare function logTerminalRead(method: string, params: {
|
|
45
|
+
terminalId?: string;
|
|
46
|
+
[key: string]: any;
|
|
47
|
+
}, uid: string, success: boolean, error?: any, metadata?: Record<string, any>): void;
|
|
48
|
+
/**
|
|
49
|
+
* Log a terminal write operation
|
|
50
|
+
*/
|
|
51
|
+
export declare function logTerminalWrite(method: string, params: {
|
|
52
|
+
terminalId?: string;
|
|
53
|
+
data?: string;
|
|
54
|
+
cols?: number;
|
|
55
|
+
rows?: number;
|
|
56
|
+
[key: string]: any;
|
|
57
|
+
}, uid: string, success: boolean, error?: any, metadata?: Record<string, any>): void;
|
|
58
|
+
/**
|
|
59
|
+
* Log a search operation
|
|
60
|
+
*/
|
|
61
|
+
export declare function logSearchRead(method: string, params: {
|
|
62
|
+
path?: string;
|
|
63
|
+
searchTerm?: string;
|
|
64
|
+
[key: string]: any;
|
|
65
|
+
}, uid: string, success: boolean, error?: any, metadata?: Record<string, any>): void;
|
|
66
|
+
/**
|
|
67
|
+
* Log an authentication event
|
|
68
|
+
*/
|
|
69
|
+
export declare function logAuth(event: string, details: Record<string, any>, level?: 'info' | 'warn' | 'error'): void;
|
|
70
|
+
/**
|
|
71
|
+
* Log connection events (client connecting, authenticated, disconnected)
|
|
72
|
+
*/
|
|
73
|
+
export declare function logConnection(event: 'connecting' | 'authenticated' | 'auth_failed' | 'disconnected' | 'ready', deviceId?: string, metadata?: Record<string, any>): void;
|
|
74
|
+
/**
|
|
75
|
+
* Log a browser proxy request
|
|
76
|
+
*/
|
|
77
|
+
export declare function logBrowserProxy(params: {
|
|
78
|
+
url?: string;
|
|
79
|
+
method?: string;
|
|
80
|
+
requestId?: string;
|
|
81
|
+
[key: string]: any;
|
|
82
|
+
}, uid: string, success: boolean, error?: any, metadata?: Record<string, any>): void;
|
|
83
|
+
declare const _default: {
|
|
84
|
+
logFsRead: typeof logFsRead;
|
|
85
|
+
logFsWrite: typeof logFsWrite;
|
|
86
|
+
logGitRead: typeof logGitRead;
|
|
87
|
+
logGitWrite: typeof logGitWrite;
|
|
88
|
+
logTerminalRead: typeof logTerminalRead;
|
|
89
|
+
logTerminalWrite: typeof logTerminalWrite;
|
|
90
|
+
logSearchRead: typeof logSearchRead;
|
|
91
|
+
logBrowserProxy: typeof logBrowserProxy;
|
|
92
|
+
logAuth: typeof logAuth;
|
|
93
|
+
logConnection: typeof logConnection;
|
|
94
|
+
};
|
|
95
|
+
export default _default;
|
|
96
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple, readable logging utility for network operations
|
|
3
|
+
*/
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
const LOG_RETENTION_DAYS = 30;
|
|
8
|
+
let logDirInitialized = false;
|
|
9
|
+
let cleanupScheduled = false;
|
|
10
|
+
/**
|
|
11
|
+
* Get log directory path (lazy - doesn't create it)
|
|
12
|
+
*/
|
|
13
|
+
function getLogDir() {
|
|
14
|
+
return path.join(process.cwd(), '.spck-editor', 'logs');
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Ensure log directory exists (lazy initialization)
|
|
18
|
+
* Called only when actually writing logs
|
|
19
|
+
*/
|
|
20
|
+
function ensureLogDirectory() {
|
|
21
|
+
if (logDirInitialized) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const logDir = getLogDir();
|
|
26
|
+
// Check if .spck-editor exists and is accessible
|
|
27
|
+
const spckEditorDir = path.join(process.cwd(), '.spck-editor');
|
|
28
|
+
if (!fs.existsSync(spckEditorDir)) {
|
|
29
|
+
// .spck-editor directory not set up yet - skip logging to file
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
// Create logs subdirectory if needed
|
|
33
|
+
if (!fs.existsSync(logDir)) {
|
|
34
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
35
|
+
}
|
|
36
|
+
logDirInitialized = true;
|
|
37
|
+
// Schedule cleanup only once, after first successful initialization
|
|
38
|
+
if (!cleanupScheduled) {
|
|
39
|
+
cleanupScheduled = true;
|
|
40
|
+
// Run cleanup after a short delay (not immediately on import)
|
|
41
|
+
setTimeout(() => {
|
|
42
|
+
cleanOldLogs();
|
|
43
|
+
setInterval(cleanOldLogs, 24 * 60 * 60 * 1000).unref();
|
|
44
|
+
}, 1000).unref();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
// Silently fail if we can't create log directory
|
|
49
|
+
// Logging will just go to console only
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Get current log file path with date
|
|
54
|
+
*/
|
|
55
|
+
function getCurrentLogFile() {
|
|
56
|
+
const date = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
|
|
57
|
+
return path.join(getLogDir(), `spck-cli-${date}.log`);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Clean up old log files (retention policy)
|
|
61
|
+
*/
|
|
62
|
+
function cleanOldLogs() {
|
|
63
|
+
try {
|
|
64
|
+
const logDir = getLogDir();
|
|
65
|
+
if (!fs.existsSync(logDir)) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const files = fs.readdirSync(logDir);
|
|
69
|
+
const now = Date.now();
|
|
70
|
+
const retentionMs = LOG_RETENTION_DAYS * 24 * 60 * 60 * 1000;
|
|
71
|
+
for (const file of files) {
|
|
72
|
+
if (file.startsWith('spck-cli-') && file.endsWith('.log')) {
|
|
73
|
+
const filePath = path.join(logDir, file);
|
|
74
|
+
const stats = fs.statSync(filePath);
|
|
75
|
+
if (now - stats.mtimeMs > retentionMs) {
|
|
76
|
+
fs.unlinkSync(filePath);
|
|
77
|
+
console.log(chalk.gray(`[Logger] Deleted old log file: ${file}`));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
// Silently fail cleanup errors
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Format timestamp for display (compact format for files)
|
|
88
|
+
* Format: MM-DD HH:MM:SS
|
|
89
|
+
*/
|
|
90
|
+
function formatTime() {
|
|
91
|
+
const now = new Date();
|
|
92
|
+
const month = String(now.getMonth() + 1).padStart(2, '0');
|
|
93
|
+
const day = String(now.getDate()).padStart(2, '0');
|
|
94
|
+
const hours = String(now.getHours()).padStart(2, '0');
|
|
95
|
+
const minutes = String(now.getMinutes()).padStart(2, '0');
|
|
96
|
+
const seconds = String(now.getSeconds()).padStart(2, '0');
|
|
97
|
+
return `${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Format timestamp for terminal display (compact format)
|
|
101
|
+
*/
|
|
102
|
+
function formatTimeCompact() {
|
|
103
|
+
const now = new Date();
|
|
104
|
+
// Format: HH:MM:SS
|
|
105
|
+
return now.toTimeString().substring(0, 8);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Format UID for display (truncate if needed)
|
|
109
|
+
*/
|
|
110
|
+
function formatUid(uid, maxLen = 12) {
|
|
111
|
+
if (uid.length <= maxLen)
|
|
112
|
+
return uid;
|
|
113
|
+
return uid.substring(0, maxLen - 3) + '...';
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Write log entry to file
|
|
117
|
+
*/
|
|
118
|
+
function writeToFile(message) {
|
|
119
|
+
try {
|
|
120
|
+
// Lazy initialization - only create log directory when actually writing
|
|
121
|
+
ensureLogDirectory();
|
|
122
|
+
if (!logDirInitialized) {
|
|
123
|
+
// Log directory couldn't be initialized, skip file logging
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const logFile = getCurrentLogFile();
|
|
127
|
+
const timestamp = formatTime();
|
|
128
|
+
fs.appendFileSync(logFile, `[${timestamp}] ${message}\n`);
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
// Silently fail file writes to not disrupt service
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Format path for display (truncate if too long)
|
|
136
|
+
*/
|
|
137
|
+
function formatPath(p, maxLen = 50) {
|
|
138
|
+
if (!p)
|
|
139
|
+
return '';
|
|
140
|
+
if (p.length <= maxLen)
|
|
141
|
+
return p;
|
|
142
|
+
return '...' + p.substring(p.length - maxLen + 3);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Format byte count as human-readable size string
|
|
146
|
+
*/
|
|
147
|
+
function formatBytes(bytes) {
|
|
148
|
+
if (bytes < 1024)
|
|
149
|
+
return `${bytes} B`;
|
|
150
|
+
if (bytes < 1024 * 1024)
|
|
151
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
152
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
153
|
+
}
|
|
154
|
+
// Debounce state for browser proxy console output
|
|
155
|
+
const BROWSER_PROXY_DEBOUNCE_MS = 1000;
|
|
156
|
+
let _browserDebounceTimer = null;
|
|
157
|
+
let _browserSuccessCount = 0;
|
|
158
|
+
let _browserTotalBytes = 0;
|
|
159
|
+
let _browserLastUid = '';
|
|
160
|
+
function flushBrowserProxyLog() {
|
|
161
|
+
if (_browserSuccessCount === 0)
|
|
162
|
+
return;
|
|
163
|
+
const timestamp = chalk.gray(formatTimeCompact());
|
|
164
|
+
const uidStr = chalk.gray(formatUid(_browserLastUid));
|
|
165
|
+
const sizeStr = chalk.gray(formatBytes(_browserTotalBytes));
|
|
166
|
+
const countStr = chalk.white(String(_browserSuccessCount));
|
|
167
|
+
console.log(`${timestamp} ${uidStr} ${chalk.green('✓')} ${chalk.blueBright('BROWSER')} ${countStr} files fetched (${sizeStr})`);
|
|
168
|
+
_browserSuccessCount = 0;
|
|
169
|
+
_browserTotalBytes = 0;
|
|
170
|
+
_browserLastUid = '';
|
|
171
|
+
_browserDebounceTimer = null;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Log a filesystem read operation
|
|
175
|
+
*/
|
|
176
|
+
export function logFsRead(method, params, uid, success, error, metadata) {
|
|
177
|
+
const filepath = params.path || params.src || params.oldpath;
|
|
178
|
+
const displayPath = formatPath(filepath);
|
|
179
|
+
const metaStr = metadata ? ` ${chalk.gray(JSON.stringify(metadata))}` : '';
|
|
180
|
+
const timestamp = chalk.gray(formatTimeCompact());
|
|
181
|
+
const uidStr = chalk.gray(formatUid(uid));
|
|
182
|
+
if (success) {
|
|
183
|
+
const msg = `${timestamp} ${uidStr} ${chalk.green('✓')} ${chalk.cyan('FS')} ${chalk.white(method.padEnd(12))} ${chalk.gray(displayPath)}${metaStr}`;
|
|
184
|
+
console.log(msg);
|
|
185
|
+
writeToFile(`[INFO] FS READ ${method} ${filepath} uid=${uid} success=true${metaStr}`);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
const errMsg = error?.message || String(error);
|
|
189
|
+
const msg = `${timestamp} ${uidStr} ${chalk.red('✗')} ${chalk.cyan('FS')} ${chalk.white(method.padEnd(12))} ${chalk.gray(displayPath)} ${chalk.red(errMsg)}`;
|
|
190
|
+
console.log(msg);
|
|
191
|
+
writeToFile(`[ERROR] FS READ ${method} ${filepath} uid=${uid} success=false error="${errMsg}"`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Log a filesystem write operation
|
|
196
|
+
*/
|
|
197
|
+
export function logFsWrite(method, params, uid, success, error, metadata) {
|
|
198
|
+
const filepath = params.path || params.src || params.target || params.oldpath;
|
|
199
|
+
const displayPath = formatPath(filepath);
|
|
200
|
+
const srcTarget = params.src && params.target
|
|
201
|
+
? `${formatPath(params.src, 25)} → ${formatPath(params.target, 25)}`
|
|
202
|
+
: displayPath;
|
|
203
|
+
const metaStr = metadata ? ` ${chalk.gray(JSON.stringify(metadata))}` : '';
|
|
204
|
+
const timestamp = chalk.gray(formatTimeCompact());
|
|
205
|
+
const uidStr = chalk.gray(formatUid(uid));
|
|
206
|
+
if (success) {
|
|
207
|
+
const msg = `${timestamp} ${uidStr} ${chalk.green('✓')} ${chalk.yellow('FS')} ${chalk.white(method.padEnd(12))} ${chalk.gray(srcTarget)}${metaStr}`;
|
|
208
|
+
console.log(msg);
|
|
209
|
+
writeToFile(`[INFO] FS WRITE ${method} ${filepath} uid=${uid} success=true${metaStr}`);
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
const errMsg = error?.message || String(error);
|
|
213
|
+
const msg = `${timestamp} ${uidStr} ${chalk.red('✗')} ${chalk.yellow('FS')} ${chalk.white(method.padEnd(12))} ${chalk.gray(srcTarget)} ${chalk.red(errMsg)}`;
|
|
214
|
+
console.log(msg);
|
|
215
|
+
writeToFile(`[ERROR] FS WRITE ${method} ${filepath} uid=${uid} success=false error="${errMsg}"`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Log a git read operation
|
|
220
|
+
*/
|
|
221
|
+
export function logGitRead(method, params, uid, success, error, metadata) {
|
|
222
|
+
const dir = formatPath(params.dir);
|
|
223
|
+
const metaStr = metadata ? ` ${chalk.gray(JSON.stringify(metadata))}` : '';
|
|
224
|
+
const timestamp = chalk.gray(formatTimeCompact());
|
|
225
|
+
const uidStr = chalk.gray(formatUid(uid));
|
|
226
|
+
if (success) {
|
|
227
|
+
const msg = `${timestamp} ${uidStr} ${chalk.green('✓')} ${chalk.magenta('GIT')} ${chalk.white(method.padEnd(12))} ${chalk.gray(dir)}${metaStr}`;
|
|
228
|
+
console.log(msg);
|
|
229
|
+
writeToFile(`[INFO] GIT READ ${method} dir=${params.dir} uid=${uid} success=true${metaStr}`);
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
const errMsg = error?.message || String(error);
|
|
233
|
+
const msg = `${timestamp} ${uidStr} ${chalk.red('✗')} ${chalk.magenta('GIT')} ${chalk.white(method.padEnd(12))} ${chalk.gray(dir)} ${chalk.red(errMsg)}`;
|
|
234
|
+
console.log(msg);
|
|
235
|
+
writeToFile(`[ERROR] GIT READ ${method} dir=${params.dir} uid=${uid} success=false error="${errMsg}"`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Log a git write operation
|
|
240
|
+
*/
|
|
241
|
+
export function logGitWrite(method, params, uid, success, error, metadata) {
|
|
242
|
+
const dir = formatPath(params.dir);
|
|
243
|
+
const details = [];
|
|
244
|
+
if (params.message)
|
|
245
|
+
details.push(`msg="${params.message.substring(0, 30)}${params.message.length > 30 ? '...' : ''}"`);
|
|
246
|
+
if (params.filepaths?.length)
|
|
247
|
+
details.push(`files=${params.filepaths.length}`);
|
|
248
|
+
if (params.ref)
|
|
249
|
+
details.push(`ref=${params.ref}`);
|
|
250
|
+
const detailStr = details.length ? ` ${chalk.gray(details.join(' '))}` : '';
|
|
251
|
+
const metaStr = metadata ? ` ${chalk.gray(JSON.stringify(metadata))}` : '';
|
|
252
|
+
const timestamp = chalk.gray(formatTimeCompact());
|
|
253
|
+
const uidStr = chalk.gray(formatUid(uid));
|
|
254
|
+
if (success) {
|
|
255
|
+
const msg = `${timestamp} ${uidStr} ${chalk.green('✓')} ${chalk.yellow('GIT')} ${chalk.white(method.padEnd(12))} ${chalk.gray(dir)}${detailStr}${metaStr}`;
|
|
256
|
+
console.log(msg);
|
|
257
|
+
writeToFile(`[INFO] GIT WRITE ${method} dir=${params.dir} uid=${uid} success=true${detailStr}${metaStr}`);
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
const errMsg = error?.message || String(error);
|
|
261
|
+
const msg = `${timestamp} ${uidStr} ${chalk.red('✗')} ${chalk.yellow('GIT')} ${chalk.white(method.padEnd(12))} ${chalk.gray(dir)} ${chalk.red(errMsg)}`;
|
|
262
|
+
console.log(msg);
|
|
263
|
+
writeToFile(`[ERROR] GIT WRITE ${method} dir=${params.dir} uid=${uid} success=false error="${errMsg}"`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Log a terminal read operation
|
|
268
|
+
*/
|
|
269
|
+
export function logTerminalRead(method, params, uid, success, error, metadata) {
|
|
270
|
+
const termId = params.terminalId || 'all';
|
|
271
|
+
const metaStr = metadata ? ` ${chalk.gray(JSON.stringify(metadata))}` : '';
|
|
272
|
+
const timestamp = chalk.gray(formatTimeCompact());
|
|
273
|
+
const uidStr = chalk.gray(formatUid(uid));
|
|
274
|
+
if (success) {
|
|
275
|
+
const msg = `${timestamp} ${uidStr} ${chalk.green('✓')} ${chalk.blue('TERM')} ${chalk.white(method.padEnd(12))} ${chalk.gray(termId)}${metaStr}`;
|
|
276
|
+
console.log(msg);
|
|
277
|
+
writeToFile(`[INFO] TERMINAL READ ${method} terminalId=${termId} uid=${uid} success=true${metaStr}`);
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
const errMsg = error?.message || String(error);
|
|
281
|
+
const msg = `${timestamp} ${uidStr} ${chalk.red('✗')} ${chalk.blue('TERM')} ${chalk.white(method.padEnd(12))} ${chalk.gray(termId)} ${chalk.red(errMsg)}`;
|
|
282
|
+
console.log(msg);
|
|
283
|
+
writeToFile(`[ERROR] TERMINAL READ ${method} terminalId=${termId} uid=${uid} success=false error="${errMsg}"`);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Log a terminal write operation
|
|
288
|
+
*/
|
|
289
|
+
export function logTerminalWrite(method, params, uid, success, error, metadata) {
|
|
290
|
+
const termId = params.terminalId || metadata?.terminalId || 'new';
|
|
291
|
+
const details = [];
|
|
292
|
+
if (params.cols && params.rows)
|
|
293
|
+
details.push(`${params.cols}x${params.rows}`);
|
|
294
|
+
if (params.data)
|
|
295
|
+
details.push(`${params.data.length}b`);
|
|
296
|
+
const detailStr = details.length ? ` ${chalk.gray(details.join(' '))}` : '';
|
|
297
|
+
const metaStr = metadata && !metadata.terminalId ? ` ${chalk.gray(JSON.stringify(metadata))}` : '';
|
|
298
|
+
const timestamp = chalk.gray(formatTimeCompact());
|
|
299
|
+
const uidStr = chalk.gray(formatUid(uid));
|
|
300
|
+
if (success) {
|
|
301
|
+
const msg = `${timestamp} ${uidStr} ${chalk.green('✓')} ${chalk.yellow('TERM')} ${chalk.white(method.padEnd(12))} ${chalk.gray(termId)}${detailStr}${metaStr}`;
|
|
302
|
+
console.log(msg);
|
|
303
|
+
writeToFile(`[INFO] TERMINAL WRITE ${method} terminalId=${termId} uid=${uid} success=true${detailStr}${metaStr}`);
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
const errMsg = error?.message || String(error);
|
|
307
|
+
const msg = `${timestamp} ${uidStr} ${chalk.red('✗')} ${chalk.yellow('TERM')} ${chalk.white(method.padEnd(12))} ${chalk.gray(termId)} ${chalk.red(errMsg)}`;
|
|
308
|
+
console.log(msg);
|
|
309
|
+
writeToFile(`[ERROR] TERMINAL WRITE ${method} terminalId=${termId} uid=${uid} success=false error="${errMsg}"`);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Log a search operation
|
|
314
|
+
*/
|
|
315
|
+
export function logSearchRead(method, params, uid, success, error, metadata) {
|
|
316
|
+
const filepath = formatPath(params.path);
|
|
317
|
+
const searchTerm = params.searchTerm ? `"${params.searchTerm.substring(0, 30)}${params.searchTerm.length > 30 ? '...' : ''}'"` : '';
|
|
318
|
+
const details = [];
|
|
319
|
+
if (searchTerm)
|
|
320
|
+
details.push(searchTerm);
|
|
321
|
+
if (metadata?.matches !== undefined)
|
|
322
|
+
details.push(`matches=${metadata.matches}`);
|
|
323
|
+
if (metadata?.method)
|
|
324
|
+
details.push(metadata.method);
|
|
325
|
+
const detailStr = details.length ? ` ${chalk.gray(details.join(' '))}` : '';
|
|
326
|
+
const metaStr = metadata && !metadata.matches && !metadata.method ? ` ${chalk.gray(JSON.stringify(metadata))}` : '';
|
|
327
|
+
const timestamp = chalk.gray(formatTimeCompact());
|
|
328
|
+
const uidStr = chalk.gray(formatUid(uid));
|
|
329
|
+
if (success) {
|
|
330
|
+
const msg = `${timestamp} ${uidStr} ${chalk.green('✓')} ${chalk.green('SEARCH')} ${chalk.white(method.padEnd(12))} ${chalk.gray(filepath)}${detailStr}${metaStr}`;
|
|
331
|
+
console.log(msg);
|
|
332
|
+
writeToFile(`[INFO] SEARCH ${method} ${params.path} searchTerm="${params.searchTerm}" uid=${uid} success=true${detailStr}${metaStr}`);
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
const errMsg = error?.message || String(error);
|
|
336
|
+
const msg = `${timestamp} ${uidStr} ${chalk.red('✗')} ${chalk.green('SEARCH')} ${chalk.white(method.padEnd(12))} ${chalk.gray(filepath)} ${chalk.red(errMsg)}`;
|
|
337
|
+
console.log(msg);
|
|
338
|
+
writeToFile(`[ERROR] SEARCH ${method} ${params.path} searchTerm="${params.searchTerm}" uid=${uid} success=false error="${errMsg}"`);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Log an authentication event
|
|
343
|
+
*/
|
|
344
|
+
export function logAuth(event, details, level = 'info') {
|
|
345
|
+
const timestamp = chalk.gray(formatTimeCompact());
|
|
346
|
+
const deviceId = details.deviceId ? chalk.gray(formatUid(details.deviceId)) : '';
|
|
347
|
+
const userId = details.userId ? chalk.gray(`user=${details.userId}`) : '';
|
|
348
|
+
const metaStr = Object.entries(details)
|
|
349
|
+
.filter(([key]) => key !== 'deviceId' && key !== 'userId')
|
|
350
|
+
.map(([key, val]) => `${key}=${val}`)
|
|
351
|
+
.join(' ');
|
|
352
|
+
let symbol;
|
|
353
|
+
let color;
|
|
354
|
+
let logLevel;
|
|
355
|
+
if (level === 'error') {
|
|
356
|
+
symbol = chalk.red('✗');
|
|
357
|
+
color = chalk.red;
|
|
358
|
+
logLevel = 'ERROR';
|
|
359
|
+
}
|
|
360
|
+
else if (level === 'warn') {
|
|
361
|
+
symbol = chalk.yellow('⚠');
|
|
362
|
+
color = chalk.yellow;
|
|
363
|
+
logLevel = 'WARN';
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
symbol = chalk.green('✓');
|
|
367
|
+
color = chalk.green;
|
|
368
|
+
logLevel = 'INFO';
|
|
369
|
+
}
|
|
370
|
+
const msg = `${timestamp} ${deviceId} ${userId} ${symbol} ${color('AUTH')} ${chalk.white(event.padEnd(20))} ${chalk.gray(metaStr)}`;
|
|
371
|
+
console.log(msg);
|
|
372
|
+
writeToFile(`[${logLevel}] AUTH ${event} ${metaStr}`);
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Log connection events (client connecting, authenticated, disconnected)
|
|
376
|
+
*/
|
|
377
|
+
export function logConnection(event, deviceId, metadata) {
|
|
378
|
+
const timestamp = chalk.gray(formatTimeCompact());
|
|
379
|
+
const deviceStr = deviceId ? chalk.gray(formatUid(deviceId)) : chalk.gray('...');
|
|
380
|
+
const metaStr = metadata ? ` ${chalk.gray(JSON.stringify(metadata))}` : '';
|
|
381
|
+
let symbol;
|
|
382
|
+
let color;
|
|
383
|
+
let logLevel;
|
|
384
|
+
switch (event) {
|
|
385
|
+
case 'connecting':
|
|
386
|
+
symbol = '🔌';
|
|
387
|
+
color = chalk.blue;
|
|
388
|
+
logLevel = 'INFO';
|
|
389
|
+
break;
|
|
390
|
+
case 'authenticated':
|
|
391
|
+
symbol = chalk.green('✓');
|
|
392
|
+
color = chalk.green;
|
|
393
|
+
logLevel = 'INFO';
|
|
394
|
+
break;
|
|
395
|
+
case 'auth_failed':
|
|
396
|
+
symbol = chalk.red('✗');
|
|
397
|
+
color = chalk.red;
|
|
398
|
+
logLevel = 'ERROR';
|
|
399
|
+
break;
|
|
400
|
+
case 'disconnected':
|
|
401
|
+
symbol = '🔌';
|
|
402
|
+
color = chalk.gray;
|
|
403
|
+
logLevel = 'INFO';
|
|
404
|
+
break;
|
|
405
|
+
case 'ready':
|
|
406
|
+
symbol = '🎉';
|
|
407
|
+
color = chalk.green;
|
|
408
|
+
logLevel = 'INFO';
|
|
409
|
+
break;
|
|
410
|
+
default:
|
|
411
|
+
symbol = 'ℹ';
|
|
412
|
+
color = chalk.gray;
|
|
413
|
+
logLevel = 'INFO';
|
|
414
|
+
}
|
|
415
|
+
const msg = `${timestamp} ${deviceStr} ${symbol} ${color('CONN')} ${chalk.white(event.padEnd(15))}${metaStr}`;
|
|
416
|
+
console.log(msg);
|
|
417
|
+
writeToFile(`[${logLevel}] CONN ${event} deviceId=${deviceId || 'unknown'}${metaStr}`);
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Log a browser proxy request
|
|
421
|
+
*/
|
|
422
|
+
export function logBrowserProxy(params, uid, success, error, metadata) {
|
|
423
|
+
const httpMethod = (params.method || 'GET').toUpperCase();
|
|
424
|
+
if (success) {
|
|
425
|
+
writeToFile(`[INFO] BROWSER PROXY ${httpMethod} ${params.url} uid=${uid} success=true status=${metadata?.status}`);
|
|
426
|
+
// Accumulate and debounce console output into a single summary line
|
|
427
|
+
_browserSuccessCount++;
|
|
428
|
+
_browserTotalBytes += metadata?.size ?? 0;
|
|
429
|
+
_browserLastUid = uid;
|
|
430
|
+
if (_browserDebounceTimer)
|
|
431
|
+
clearTimeout(_browserDebounceTimer);
|
|
432
|
+
_browserDebounceTimer = setTimeout(flushBrowserProxyLog, BROWSER_PROXY_DEBOUNCE_MS);
|
|
433
|
+
}
|
|
434
|
+
else {
|
|
435
|
+
const displayUrl = formatPath(params.url, 60);
|
|
436
|
+
const timestamp = chalk.gray(formatTimeCompact());
|
|
437
|
+
const uidStr = chalk.gray(formatUid(uid));
|
|
438
|
+
const errMsg = error?.message || String(error);
|
|
439
|
+
const msg = `${timestamp} ${uidStr} ${chalk.red('✗')} ${chalk.blueBright('BROWSER')} ${chalk.white(httpMethod.padEnd(7))} ${chalk.gray(displayUrl)} ${chalk.red(errMsg)}`;
|
|
440
|
+
console.log(msg);
|
|
441
|
+
writeToFile(`[ERROR] BROWSER PROXY ${httpMethod} ${params.url} uid=${uid} success=false error="${errMsg}"`);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
export default {
|
|
445
|
+
logFsRead,
|
|
446
|
+
logFsWrite,
|
|
447
|
+
logGitRead,
|
|
448
|
+
logGitWrite,
|
|
449
|
+
logTerminalRead,
|
|
450
|
+
logTerminalWrite,
|
|
451
|
+
logSearchRead,
|
|
452
|
+
logBrowserProxy,
|
|
453
|
+
logAuth,
|
|
454
|
+
logConnection,
|
|
455
|
+
};
|
|
456
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project directory management with symlink support
|
|
3
|
+
* .spck-editor/ is a regular directory with .spck-editor/config symlinked to ~/.spck-editor/projects/{id}
|
|
4
|
+
* This prevents accidental git commits of secrets while avoiding cross-device link errors
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Generate a consistent project ID from the project root path
|
|
8
|
+
*/
|
|
9
|
+
export declare function generateProjectId(projectRoot: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Get the home directory location for a project's data
|
|
12
|
+
*/
|
|
13
|
+
export declare function getProjectDataPath(projectRoot: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Get the .spck-editor directory path in the project
|
|
16
|
+
*/
|
|
17
|
+
export declare function getProjectDirPath(projectRoot: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Get the config symlink path (.spck-editor/config)
|
|
20
|
+
*/
|
|
21
|
+
export declare function getConfigSymlinkPath(projectRoot: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* @deprecated Use getConfigSymlinkPath() instead
|
|
24
|
+
* Legacy compatibility - returns config symlink path
|
|
25
|
+
*/
|
|
26
|
+
export declare function getProjectSymlinkPath(projectRoot: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* Check if the project directory exists and is properly set up
|
|
29
|
+
*/
|
|
30
|
+
export declare function isProjectDirSetup(projectRoot: string): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Setup the project directory with config symlink
|
|
33
|
+
* Creates ~/.spck-editor/projects/{project_id}/ and symlinks .spck-editor/config to it
|
|
34
|
+
*/
|
|
35
|
+
export declare function setupProjectDir(projectRoot: string): void;
|
|
36
|
+
/**
|
|
37
|
+
* Ensure project directory is set up, creating if needed
|
|
38
|
+
*/
|
|
39
|
+
export declare function ensureProjectDir(projectRoot: string): void;
|
|
40
|
+
/**
|
|
41
|
+
* Get the absolute path to a file within the project directory
|
|
42
|
+
* Files go in .spck-editor/{filename} (local) or .spck-editor/config/{filename} (symlinked)
|
|
43
|
+
* Config files (like connection-settings.json) go in the config subdirectory
|
|
44
|
+
*/
|
|
45
|
+
export declare function getProjectFilePath(projectRoot: string, filename: string): string;
|
|
46
|
+
/**
|
|
47
|
+
* Remove project directory and all associated data
|
|
48
|
+
* WARNING: This deletes the data directory in home and the local .spck-editor directory
|
|
49
|
+
*/
|
|
50
|
+
export declare function removeProjectDir(projectRoot: string): void;
|
|
51
|
+
//# sourceMappingURL=project-dir.d.ts.map
|