@b0xs/recorder 1.0.0

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.
Files changed (46) hide show
  1. package/README.md +89 -0
  2. package/dist/api/client.d.ts +111 -0
  3. package/dist/api/client.d.ts.map +1 -0
  4. package/dist/api/client.js +186 -0
  5. package/dist/api/client.js.map +1 -0
  6. package/dist/cli/commands/init.d.ts +7 -0
  7. package/dist/cli/commands/init.d.ts.map +1 -0
  8. package/dist/cli/commands/init.js +104 -0
  9. package/dist/cli/commands/init.js.map +1 -0
  10. package/dist/cli/commands/login.d.ts +7 -0
  11. package/dist/cli/commands/login.d.ts.map +1 -0
  12. package/dist/cli/commands/login.js +154 -0
  13. package/dist/cli/commands/login.js.map +1 -0
  14. package/dist/cli/commands/record.d.ts +14 -0
  15. package/dist/cli/commands/record.d.ts.map +1 -0
  16. package/dist/cli/commands/record.js +244 -0
  17. package/dist/cli/commands/record.js.map +1 -0
  18. package/dist/core/chunk-uploader.d.ts +52 -0
  19. package/dist/core/chunk-uploader.d.ts.map +1 -0
  20. package/dist/core/chunk-uploader.js +180 -0
  21. package/dist/core/chunk-uploader.js.map +1 -0
  22. package/dist/core/pty-manager.d.ts +72 -0
  23. package/dist/core/pty-manager.d.ts.map +1 -0
  24. package/dist/core/pty-manager.js +205 -0
  25. package/dist/core/pty-manager.js.map +1 -0
  26. package/dist/core/recorder.d.ts +104 -0
  27. package/dist/core/recorder.d.ts.map +1 -0
  28. package/dist/core/recorder.js +330 -0
  29. package/dist/core/recorder.js.map +1 -0
  30. package/dist/core/stream-client.d.ts +62 -0
  31. package/dist/core/stream-client.d.ts.map +1 -0
  32. package/dist/core/stream-client.js +185 -0
  33. package/dist/core/stream-client.js.map +1 -0
  34. package/dist/index.d.ts +8 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +75 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/storage/auth-store.d.ts +37 -0
  39. package/dist/storage/auth-store.d.ts.map +1 -0
  40. package/dist/storage/auth-store.js +168 -0
  41. package/dist/storage/auth-store.js.map +1 -0
  42. package/dist/storage/config-store.d.ts +74 -0
  43. package/dist/storage/config-store.d.ts.map +1 -0
  44. package/dist/storage/config-store.js +164 -0
  45. package/dist/storage/config-store.js.map +1 -0
  46. package/package.json +54 -0
package/dist/index.js ADDED
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * BOXS Recorder CLI
5
+ *
6
+ * Main entry point for the CLI tool
7
+ */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const commander_1 = require("commander");
13
+ const chalk_1 = __importDefault(require("chalk"));
14
+ const login_1 = require("./cli/commands/login");
15
+ const init_1 = require("./cli/commands/init");
16
+ const record_1 = require("./cli/commands/record");
17
+ const program = new commander_1.Command();
18
+ program
19
+ .name('boxs')
20
+ .description('CLI tool for recording terminal sessions to BOXS platform')
21
+ .version('1.0.0');
22
+ // Login command
23
+ program
24
+ .command('login')
25
+ .description('Authenticate with your BOXS API key')
26
+ .action(async () => {
27
+ try {
28
+ await (0, login_1.loginCommand)();
29
+ }
30
+ catch (error) {
31
+ console.error(chalk_1.default.red(`\n✗ Error: ${error.message}\n`));
32
+ process.exit(1);
33
+ }
34
+ });
35
+ // Init command
36
+ program
37
+ .command('init')
38
+ .description('Initialize configuration file')
39
+ .action(async () => {
40
+ try {
41
+ await (0, init_1.initCommand)();
42
+ }
43
+ catch (error) {
44
+ console.error(chalk_1.default.red(`\n✗ Error: ${error.message}\n`));
45
+ process.exit(1);
46
+ }
47
+ });
48
+ // Record command
49
+ program
50
+ .command('record [command]')
51
+ .description('Start recording a terminal session')
52
+ .option('-t, --title <title>', 'Session title')
53
+ .option('-d, --description <description>', 'Session description')
54
+ .option('-v, --visibility <visibility>', 'Session visibility (public, private, unlisted, team)')
55
+ .option('-s, --stream', 'Enable live streaming')
56
+ .action(async (command, options) => {
57
+ try {
58
+ await (0, record_1.recordCommand)({
59
+ ...options,
60
+ command,
61
+ stream: options.stream === true,
62
+ });
63
+ }
64
+ catch (error) {
65
+ console.error(chalk_1.default.red(`\n✗ Error: ${error.message}\n`));
66
+ process.exit(1);
67
+ }
68
+ });
69
+ // Parse arguments
70
+ program.parse(process.argv);
71
+ // Show help if no command provided
72
+ if (!process.argv.slice(2).length) {
73
+ program.outputHelp();
74
+ }
75
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAEA;;;;GAIG;;;;;AAEH,yCAAoC;AACpC,kDAA0B;AAC1B,gDAAoD;AACpD,8CAAkD;AAClD,kDAAsD;AAEtD,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,MAAM,CAAC;KACZ,WAAW,CAAC,2DAA2D,CAAC;KACxE,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,gBAAgB;AAChB,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,qCAAqC,CAAC;KAClD,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,IAAI,CAAC;QACH,MAAM,IAAA,oBAAY,GAAE,CAAC;IACvB,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,cAAc,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,eAAe;AACf,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,+BAA+B,CAAC;KAC5C,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,IAAI,CAAC;QACH,MAAM,IAAA,kBAAW,GAAE,CAAC;IACtB,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,cAAc,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,iBAAiB;AACjB,OAAO;KACJ,OAAO,CAAC,kBAAkB,CAAC;KAC3B,WAAW,CAAC,oCAAoC,CAAC;KACjD,MAAM,CAAC,qBAAqB,EAAE,eAAe,CAAC;KAC9C,MAAM,CAAC,iCAAiC,EAAE,qBAAqB,CAAC;KAChE,MAAM,CAAC,+BAA+B,EAAE,sDAAsD,CAAC;KAC/F,MAAM,CAAC,cAAc,EAAE,uBAAuB,CAAC;KAC/C,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;IACjC,IAAI,CAAC;QACH,MAAM,IAAA,sBAAa,EAAC;YAClB,GAAG,OAAO;YACV,OAAO;YACP,MAAM,EAAE,OAAO,CAAC,MAAM,KAAK,IAAI;SAChC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,cAAc,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,kBAAkB;AAClB,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAE5B,mCAAmC;AACnC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAClC,OAAO,CAAC,UAAU,EAAE,CAAC;AACvB,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Authentication Storage
3
+ *
4
+ * Securely stores API keys using OS keychain (keytar) with encrypted file fallback
5
+ */
6
+ export declare class AuthStore {
7
+ /**
8
+ * Get API key from secure storage
9
+ */
10
+ getApiKey(): Promise<string | null>;
11
+ /**
12
+ * Save API key to secure storage
13
+ */
14
+ setApiKey(apiKey: string): Promise<void>;
15
+ /**
16
+ * Delete API key from secure storage
17
+ */
18
+ deleteApiKey(): Promise<void>;
19
+ /**
20
+ * Check if API key exists
21
+ */
22
+ hasApiKey(): Promise<boolean>;
23
+ /**
24
+ * Get API key from encrypted file (fallback)
25
+ */
26
+ private getApiKeyFromFile;
27
+ /**
28
+ * Save API key to encrypted file (fallback)
29
+ */
30
+ private saveApiKeyToFile;
31
+ /**
32
+ * Get machine-specific key for encryption
33
+ * Uses hostname + username as seed for deterministic key generation
34
+ */
35
+ private getMachineKey;
36
+ }
37
+ //# sourceMappingURL=auth-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-store.d.ts","sourceRoot":"","sources":["../../src/storage/auth-store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH,qBAAa,SAAS;IACpB;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAmBzC;;OAEG;IACG,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAa9C;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAgBnC;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAKnC;;OAEG;YACW,iBAAiB;IA0B/B;;OAEG;YACW,gBAAgB;IAyB9B;;;OAGG;YACW,aAAa;CAI5B"}
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+ /**
3
+ * Authentication Storage
4
+ *
5
+ * Securely stores API keys using OS keychain (keytar) with encrypted file fallback
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ exports.AuthStore = void 0;
42
+ const keytar = __importStar(require("keytar"));
43
+ const fs = __importStar(require("fs/promises"));
44
+ const path = __importStar(require("path"));
45
+ const os = __importStar(require("os"));
46
+ const crypto = __importStar(require("crypto"));
47
+ const SERVICE_NAME = 'boxs-recorder';
48
+ const ACCOUNT_NAME = 'api-key';
49
+ const CREDENTIALS_FILE = path.join(os.homedir(), '.boxs', 'credentials.json');
50
+ class AuthStore {
51
+ /**
52
+ * Get API key from secure storage
53
+ */
54
+ async getApiKey() {
55
+ // Try OS keychain first
56
+ try {
57
+ const apiKey = await keytar.getPassword(SERVICE_NAME, ACCOUNT_NAME);
58
+ if (apiKey) {
59
+ return apiKey;
60
+ }
61
+ }
62
+ catch (error) {
63
+ console.warn('Failed to access OS keychain, trying encrypted file fallback');
64
+ }
65
+ // Fallback to encrypted file
66
+ try {
67
+ return await this.getApiKeyFromFile();
68
+ }
69
+ catch (error) {
70
+ return null;
71
+ }
72
+ }
73
+ /**
74
+ * Save API key to secure storage
75
+ */
76
+ async setApiKey(apiKey) {
77
+ // Try OS keychain first
78
+ try {
79
+ await keytar.setPassword(SERVICE_NAME, ACCOUNT_NAME, apiKey);
80
+ return;
81
+ }
82
+ catch (error) {
83
+ console.warn('Failed to save to OS keychain, using encrypted file fallback');
84
+ }
85
+ // Fallback to encrypted file
86
+ await this.saveApiKeyToFile(apiKey);
87
+ }
88
+ /**
89
+ * Delete API key from secure storage
90
+ */
91
+ async deleteApiKey() {
92
+ // Delete from OS keychain
93
+ try {
94
+ await keytar.deletePassword(SERVICE_NAME, ACCOUNT_NAME);
95
+ }
96
+ catch (error) {
97
+ // Ignore errors
98
+ }
99
+ // Delete encrypted file
100
+ try {
101
+ await fs.unlink(CREDENTIALS_FILE);
102
+ }
103
+ catch (error) {
104
+ // Ignore errors
105
+ }
106
+ }
107
+ /**
108
+ * Check if API key exists
109
+ */
110
+ async hasApiKey() {
111
+ const apiKey = await this.getApiKey();
112
+ return apiKey !== null;
113
+ }
114
+ /**
115
+ * Get API key from encrypted file (fallback)
116
+ */
117
+ async getApiKeyFromFile() {
118
+ try {
119
+ const data = await fs.readFile(CREDENTIALS_FILE, 'utf-8');
120
+ const parsed = JSON.parse(data);
121
+ if (!parsed.encryptedApiKey || !parsed.iv) {
122
+ return null;
123
+ }
124
+ // Decrypt using machine ID as key
125
+ const key = await this.getMachineKey();
126
+ const decipher = crypto.createDecipheriv('aes-256-cbc', key, Buffer.from(parsed.iv, 'hex'));
127
+ let decrypted = decipher.update(parsed.encryptedApiKey, 'hex', 'utf-8');
128
+ decrypted += decipher.final('utf-8');
129
+ return decrypted;
130
+ }
131
+ catch (error) {
132
+ return null;
133
+ }
134
+ }
135
+ /**
136
+ * Save API key to encrypted file (fallback)
137
+ */
138
+ async saveApiKeyToFile(apiKey) {
139
+ // Ensure directory exists
140
+ const dir = path.dirname(CREDENTIALS_FILE);
141
+ await fs.mkdir(dir, { recursive: true });
142
+ // Encrypt using machine ID as key
143
+ const key = await this.getMachineKey();
144
+ const iv = crypto.randomBytes(16);
145
+ const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
146
+ let encrypted = cipher.update(apiKey, 'utf-8', 'hex');
147
+ encrypted += cipher.final('hex');
148
+ // Save to file
149
+ const data = {
150
+ encryptedApiKey: encrypted,
151
+ iv: iv.toString('hex'),
152
+ createdAt: new Date().toISOString(),
153
+ };
154
+ await fs.writeFile(CREDENTIALS_FILE, JSON.stringify(data, null, 2), {
155
+ mode: 0o600, // Owner read/write only
156
+ });
157
+ }
158
+ /**
159
+ * Get machine-specific key for encryption
160
+ * Uses hostname + username as seed for deterministic key generation
161
+ */
162
+ async getMachineKey() {
163
+ const seed = `${os.hostname()}-${os.userInfo().username}-boxs-recorder`;
164
+ return crypto.scryptSync(seed, 'salt', 32);
165
+ }
166
+ }
167
+ exports.AuthStore = AuthStore;
168
+ //# sourceMappingURL=auth-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-store.js","sourceRoot":"","sources":["../../src/storage/auth-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Configuration Storage
3
+ *
4
+ * Manages user configuration file at ~/.boxs/config.json
5
+ */
6
+ export interface RecorderConfig {
7
+ apiUrl: string;
8
+ defaults: {
9
+ visibility: 'public' | 'private' | 'unlisted' | 'team';
10
+ chunkDuration: number;
11
+ };
12
+ recorder: {
13
+ promptPatterns: string[];
14
+ maxBufferedChunks: number;
15
+ uploadRetries: number;
16
+ };
17
+ }
18
+ export declare class ConfigStore {
19
+ private conf;
20
+ constructor();
21
+ /**
22
+ * Get full configuration
23
+ */
24
+ getConfig(): RecorderConfig;
25
+ /**
26
+ * Get API URL
27
+ */
28
+ getApiUrl(): string;
29
+ /**
30
+ * Set API URL
31
+ */
32
+ setApiUrl(url: string): void;
33
+ /**
34
+ * Get default visibility
35
+ */
36
+ getDefaultVisibility(): 'public' | 'private' | 'unlisted' | 'team';
37
+ /**
38
+ * Set default visibility
39
+ */
40
+ setDefaultVisibility(visibility: 'public' | 'private' | 'unlisted' | 'team'): void;
41
+ /**
42
+ * Get chunk duration
43
+ */
44
+ getChunkDuration(): number;
45
+ /**
46
+ * Set chunk duration
47
+ */
48
+ setChunkDuration(duration: number): void;
49
+ /**
50
+ * Get prompt patterns for command detection
51
+ */
52
+ getPromptPatterns(): string[];
53
+ /**
54
+ * Add custom prompt pattern
55
+ */
56
+ addPromptPattern(pattern: string): void;
57
+ /**
58
+ * Get max buffered chunks
59
+ */
60
+ getMaxBufferedChunks(): number;
61
+ /**
62
+ * Get upload retry count
63
+ */
64
+ getUploadRetries(): number;
65
+ /**
66
+ * Reset to default configuration
67
+ */
68
+ reset(): void;
69
+ /**
70
+ * Get config file path
71
+ */
72
+ getConfigPath(): string;
73
+ }
74
+ //# sourceMappingURL=config-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-store.d.ts","sourceRoot":"","sources":["../../src/storage/config-store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE;QACR,UAAU,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;QACvD,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,QAAQ,EAAE;QACR,cAAc,EAAE,MAAM,EAAE,CAAC;QACzB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;CACH;AAmBD,qBAAa,WAAW;IACtB,OAAO,CAAC,IAAI,CAAuB;;IAkDnC;;OAEG;IACH,SAAS,IAAI,cAAc;IAI3B;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAI5B;;OAEG;IACH,oBAAoB,IAAI,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM;IAIlE;;OAEG;IACH,oBAAoB,CAAC,UAAU,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,IAAI;IAIlF;;OAEG;IACH,gBAAgB,IAAI,MAAM;IAI1B;;OAEG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAOxC;;OAEG;IACH,iBAAiB,IAAI,MAAM,EAAE;IAI7B;;OAEG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAQvC;;OAEG;IACH,oBAAoB,IAAI,MAAM;IAI9B;;OAEG;IACH,gBAAgB,IAAI,MAAM;IAI1B;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,aAAa,IAAI,MAAM;CAGxB"}
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ /**
3
+ * Configuration Storage
4
+ *
5
+ * Manages user configuration file at ~/.boxs/config.json
6
+ */
7
+ var __importDefault = (this && this.__importDefault) || function (mod) {
8
+ return (mod && mod.__esModule) ? mod : { "default": mod };
9
+ };
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.ConfigStore = void 0;
12
+ const conf_1 = __importDefault(require("conf"));
13
+ const DEFAULT_CONFIG = {
14
+ apiUrl: 'https://boxs.sh',
15
+ defaults: {
16
+ visibility: 'private',
17
+ chunkDuration: 60000, // 60 seconds
18
+ },
19
+ recorder: {
20
+ promptPatterns: [
21
+ '\\$\\s$', // $
22
+ '#\\s$', // #
23
+ '[\\w@\\-]+:[^\\$#]*[\\$#]\\s$', // user@host:path$
24
+ ],
25
+ maxBufferedChunks: 10,
26
+ uploadRetries: 5,
27
+ },
28
+ };
29
+ class ConfigStore {
30
+ constructor() {
31
+ this.conf = new conf_1.default({
32
+ projectName: 'boxs',
33
+ defaults: DEFAULT_CONFIG,
34
+ schema: {
35
+ apiUrl: {
36
+ type: 'string',
37
+ format: 'uri',
38
+ },
39
+ defaults: {
40
+ type: 'object',
41
+ properties: {
42
+ visibility: {
43
+ type: 'string',
44
+ enum: ['public', 'private', 'unlisted', 'team'],
45
+ },
46
+ chunkDuration: {
47
+ type: 'number',
48
+ minimum: 10000,
49
+ maximum: 300000,
50
+ },
51
+ },
52
+ },
53
+ recorder: {
54
+ type: 'object',
55
+ properties: {
56
+ promptPatterns: {
57
+ type: 'array',
58
+ items: {
59
+ type: 'string',
60
+ },
61
+ },
62
+ maxBufferedChunks: {
63
+ type: 'number',
64
+ minimum: 1,
65
+ maximum: 100,
66
+ },
67
+ uploadRetries: {
68
+ type: 'number',
69
+ minimum: 0,
70
+ maximum: 10,
71
+ },
72
+ },
73
+ },
74
+ },
75
+ });
76
+ }
77
+ /**
78
+ * Get full configuration
79
+ */
80
+ getConfig() {
81
+ return this.conf.store;
82
+ }
83
+ /**
84
+ * Get API URL
85
+ */
86
+ getApiUrl() {
87
+ return this.conf.get('apiUrl');
88
+ }
89
+ /**
90
+ * Set API URL
91
+ */
92
+ setApiUrl(url) {
93
+ this.conf.set('apiUrl', url);
94
+ }
95
+ /**
96
+ * Get default visibility
97
+ */
98
+ getDefaultVisibility() {
99
+ return this.conf.get('defaults.visibility');
100
+ }
101
+ /**
102
+ * Set default visibility
103
+ */
104
+ setDefaultVisibility(visibility) {
105
+ this.conf.set('defaults.visibility', visibility);
106
+ }
107
+ /**
108
+ * Get chunk duration
109
+ */
110
+ getChunkDuration() {
111
+ return this.conf.get('defaults.chunkDuration');
112
+ }
113
+ /**
114
+ * Set chunk duration
115
+ */
116
+ setChunkDuration(duration) {
117
+ if (duration < 10000 || duration > 300000) {
118
+ throw new Error('Chunk duration must be between 10s and 300s');
119
+ }
120
+ this.conf.set('defaults.chunkDuration', duration);
121
+ }
122
+ /**
123
+ * Get prompt patterns for command detection
124
+ */
125
+ getPromptPatterns() {
126
+ return this.conf.get('recorder.promptPatterns');
127
+ }
128
+ /**
129
+ * Add custom prompt pattern
130
+ */
131
+ addPromptPattern(pattern) {
132
+ const patterns = this.getPromptPatterns();
133
+ if (!patterns.includes(pattern)) {
134
+ patterns.push(pattern);
135
+ this.conf.set('recorder.promptPatterns', patterns);
136
+ }
137
+ }
138
+ /**
139
+ * Get max buffered chunks
140
+ */
141
+ getMaxBufferedChunks() {
142
+ return this.conf.get('recorder.maxBufferedChunks');
143
+ }
144
+ /**
145
+ * Get upload retry count
146
+ */
147
+ getUploadRetries() {
148
+ return this.conf.get('recorder.uploadRetries');
149
+ }
150
+ /**
151
+ * Reset to default configuration
152
+ */
153
+ reset() {
154
+ this.conf.clear();
155
+ }
156
+ /**
157
+ * Get config file path
158
+ */
159
+ getConfigPath() {
160
+ return this.conf.path;
161
+ }
162
+ }
163
+ exports.ConfigStore = ConfigStore;
164
+ //# sourceMappingURL=config-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-store.js","sourceRoot":"","sources":["../../src/storage/config-store.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@b0xs/recorder",
3
+ "version": "1.0.0",
4
+ "description": "CLI tool for recording terminal sessions to BOXS platform",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "boxs": "./dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "dev": "tsc --watch",
12
+ "test": "jest",
13
+ "prepublishOnly": "echo 'skipping build — dist already built'"
14
+ },
15
+ "keywords": [
16
+ "terminal",
17
+ "recording",
18
+ "session",
19
+ "cli",
20
+ "pentesting",
21
+ "boxs"
22
+ ],
23
+ "author": "BOXS",
24
+ "license": "MIT",
25
+ "dependencies": {
26
+ "@b0xs/binary": "^1.1.0",
27
+ "axios": "^1.6.0",
28
+ "chalk": "^4.1.2",
29
+ "commander": "^12.1.0",
30
+ "conf": "^10.2.0",
31
+ "keytar": "^7.9.0",
32
+ "node-pty": "^1.0.0",
33
+ "ora": "^5.4.1",
34
+ "socket.io-client": "^4.7.2",
35
+ "uuid": "^9.0.0"
36
+ },
37
+ "devDependencies": {
38
+ "@types/jest": "^29.0.0",
39
+ "@types/node": "^20.0.0",
40
+ "jest": "^29.0.0",
41
+ "ts-jest": "^29.1.0",
42
+ "typescript": "^5.0.0"
43
+ },
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "https://github.com/ozipi/recorder"
47
+ },
48
+ "files": [
49
+ "dist"
50
+ ],
51
+ "engines": {
52
+ "node": ">=18.0.0"
53
+ }
54
+ }