oversky 0.1.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 (49) hide show
  1. package/dist/auth.d.ts +26 -0
  2. package/dist/auth.js +221 -0
  3. package/dist/auth.js.map +1 -0
  4. package/dist/config.d.ts +20 -0
  5. package/dist/config.js +52 -0
  6. package/dist/config.js.map +1 -0
  7. package/dist/connection.d.ts +14 -0
  8. package/dist/connection.js +93 -0
  9. package/dist/connection.js.map +1 -0
  10. package/dist/executor.d.ts +20 -0
  11. package/dist/executor.js +187 -0
  12. package/dist/executor.js.map +1 -0
  13. package/dist/heartbeat.d.ts +10 -0
  14. package/dist/heartbeat.js +27 -0
  15. package/dist/heartbeat.js.map +1 -0
  16. package/dist/index.d.ts +2 -0
  17. package/dist/index.js +172 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/permissions.d.ts +17 -0
  20. package/dist/permissions.js +60 -0
  21. package/dist/permissions.js.map +1 -0
  22. package/dist/registry.d.ts +10 -0
  23. package/dist/registry.js +23 -0
  24. package/dist/registry.js.map +1 -0
  25. package/dist/security.d.ts +18 -0
  26. package/dist/security.js +181 -0
  27. package/dist/security.js.map +1 -0
  28. package/dist/tools/bash.d.ts +15 -0
  29. package/dist/tools/bash.js +58 -0
  30. package/dist/tools/bash.js.map +1 -0
  31. package/dist/tools/edit.d.ts +19 -0
  32. package/dist/tools/edit.js +49 -0
  33. package/dist/tools/edit.js.map +1 -0
  34. package/dist/tools/glob.d.ts +13 -0
  35. package/dist/tools/glob.js +34 -0
  36. package/dist/tools/glob.js.map +1 -0
  37. package/dist/tools/grep.d.ts +21 -0
  38. package/dist/tools/grep.js +95 -0
  39. package/dist/tools/grep.js.map +1 -0
  40. package/dist/tools/read.d.ts +14 -0
  41. package/dist/tools/read.js +31 -0
  42. package/dist/tools/read.js.map +1 -0
  43. package/dist/tools/write.d.ts +14 -0
  44. package/dist/tools/write.js +47 -0
  45. package/dist/tools/write.js.map +1 -0
  46. package/dist/ui.d.ts +12 -0
  47. package/dist/ui.js +77 -0
  48. package/dist/ui.js.map +1 -0
  49. package/package.json +67 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { Socket } from 'socket.io-client';
2
+ /**
3
+ * Start sending periodic heartbeats to keep the daemon's Redis slot alive.
4
+ * Server-side TTL is 45s, so 15s interval gives 3 chances.
5
+ */
6
+ export declare function startHeartbeat(socket: Socket, daemonId: string): void;
7
+ /**
8
+ * Stop the heartbeat interval.
9
+ */
10
+ export declare function stopHeartbeat(): void;
@@ -0,0 +1,27 @@
1
+ const HEARTBEAT_INTERVAL = 15_000; // 15 seconds
2
+ let heartbeatTimer = null;
3
+ /**
4
+ * Start sending periodic heartbeats to keep the daemon's Redis slot alive.
5
+ * Server-side TTL is 45s, so 15s interval gives 3 chances.
6
+ */
7
+ export function startHeartbeat(socket, daemonId) {
8
+ stopHeartbeat();
9
+ const send = () => {
10
+ if (socket.connected) {
11
+ socket.emit('daemon:heartbeat', { daemonId });
12
+ }
13
+ };
14
+ // Send immediately, then every 15s
15
+ send();
16
+ heartbeatTimer = setInterval(send, HEARTBEAT_INTERVAL);
17
+ }
18
+ /**
19
+ * Stop the heartbeat interval.
20
+ */
21
+ export function stopHeartbeat() {
22
+ if (heartbeatTimer) {
23
+ clearInterval(heartbeatTimer);
24
+ heartbeatTimer = null;
25
+ }
26
+ }
27
+ //# sourceMappingURL=heartbeat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heartbeat.js","sourceRoot":"","sources":["../src/heartbeat.ts"],"names":[],"mappings":"AAEA,MAAM,kBAAkB,GAAG,MAAM,CAAC,CAAC,aAAa;AAEhD,IAAI,cAAc,GAA0C,IAAI,CAAC;AAEjE;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,QAAgB;IAC7D,aAAa,EAAE,CAAC;IAEhB,MAAM,IAAI,GAAG,GAAG,EAAE;QAChB,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACrB,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;QAChD,CAAC;IACH,CAAC,CAAC;IAEF,mCAAmC;IACnC,IAAI,EAAE,CAAC;IACP,cAAc,GAAG,WAAW,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC;AACzD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,IAAI,cAAc,EAAE,CAAC;QACnB,aAAa,CAAC,cAAc,CAAC,CAAC;QAC9B,cAAc,GAAG,IAAI,CAAC;IACxB,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,172 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import chalk from 'chalk';
4
+ import { readFileSync } from 'node:fs';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { dirname, join } from 'node:path';
7
+ import { loadConfig, saveConfig } from './config.js';
8
+ import { getToken, loginFlow, loginPrompt, loginWithCredentials, loginWithUrl, removeToken } from './auth.js';
9
+ import { generateDaemonId } from './registry.js';
10
+ import { connectDaemon } from './connection.js';
11
+ import { setSkipPermissions } from './permissions.js';
12
+ import { showHeader, showError } from './ui.js';
13
+ const __dirname = dirname(fileURLToPath(import.meta.url));
14
+ const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
15
+ const program = new Command();
16
+ program
17
+ .name('oversky')
18
+ .description('OverSky — run AI agents directly on your machine')
19
+ .version(pkg.version);
20
+ program
21
+ .command('start')
22
+ .description('Start the daemon and connect to the OverSky server')
23
+ .option('-s, --server <url>', 'Server URL')
24
+ .option('-c, --cwd <path>', 'Working directory', process.cwd())
25
+ .option('--dangerously-skip-permissions', 'Skip all permission prompts')
26
+ .action(async (options) => {
27
+ const config = loadConfig();
28
+ const serverUrl = options.server || config.serverUrl;
29
+ const cwd = options.cwd;
30
+ if (options.dangerouslySkipPermissions) {
31
+ setSkipPermissions(true);
32
+ console.log(chalk.yellow(' WARNING: Permission prompts disabled'));
33
+ }
34
+ // Get or prompt for auth token
35
+ let token = getToken();
36
+ if (!token) {
37
+ console.log(chalk.yellow(' No authentication token found. Log in to continue.\n'));
38
+ try {
39
+ token = await loginWithUrl(serverUrl);
40
+ }
41
+ catch (err) {
42
+ console.log(chalk.dim(` URL login failed: ${err instanceof Error ? err.message : err}`));
43
+ console.log(chalk.dim(' Falling back to email/password login.\n'));
44
+ try {
45
+ token = await loginWithCredentials(serverUrl);
46
+ }
47
+ catch (credErr) {
48
+ console.log(chalk.dim(` Credential login failed: ${credErr instanceof Error ? credErr.message : credErr}`));
49
+ console.log(chalk.dim(' Falling back to manual token entry.'));
50
+ token = await loginPrompt();
51
+ }
52
+ }
53
+ if (!token) {
54
+ showError('No token provided. Run "oversky login" first.');
55
+ process.exit(1);
56
+ }
57
+ }
58
+ const daemonId = generateDaemonId(cwd);
59
+ showHeader(serverUrl, cwd, daemonId);
60
+ const { disconnect } = connectDaemon(serverUrl, token, cwd, config);
61
+ // Handle graceful shutdown
62
+ const shutdown = () => {
63
+ console.log(chalk.dim('\n Shutting down...'));
64
+ disconnect();
65
+ process.exit(0);
66
+ };
67
+ process.on('SIGINT', shutdown);
68
+ process.on('SIGTERM', shutdown);
69
+ });
70
+ program
71
+ .command('login')
72
+ .description('Authenticate with the OverSky server')
73
+ .option('-s, --server <url>', 'Server URL')
74
+ .option('--password', 'Use email/password instead of browser login')
75
+ .option('--browser', 'Use browser OAuth callback flow')
76
+ .option('--token', 'Paste a token manually')
77
+ .action(async (options) => {
78
+ const config = loadConfig();
79
+ const serverUrl = options.server || config.serverUrl;
80
+ try {
81
+ let token;
82
+ if (options.token) {
83
+ token = await loginPrompt();
84
+ }
85
+ else if (options.browser) {
86
+ token = await loginFlow(serverUrl);
87
+ }
88
+ else if (options.password) {
89
+ token = await loginWithCredentials(serverUrl);
90
+ }
91
+ else {
92
+ // Default: device code flow — opens URL in browser
93
+ token = await loginWithUrl(serverUrl);
94
+ }
95
+ if (token) {
96
+ console.log(chalk.green('\n Login successful! Token saved.'));
97
+ }
98
+ else {
99
+ showError('No token received.');
100
+ process.exit(1);
101
+ }
102
+ }
103
+ catch (err) {
104
+ showError(err instanceof Error ? err.message : String(err));
105
+ process.exit(1);
106
+ }
107
+ });
108
+ program
109
+ .command('logout')
110
+ .description('Remove saved authentication token')
111
+ .action(() => {
112
+ removeToken();
113
+ console.log(chalk.green(' Logged out. Token removed.'));
114
+ });
115
+ program
116
+ .command('status')
117
+ .description('Show daemon configuration and connection status')
118
+ .option('-c, --cwd <path>', 'Working directory', process.cwd())
119
+ .action((options) => {
120
+ const config = loadConfig();
121
+ const token = getToken();
122
+ const daemonId = generateDaemonId(options.cwd);
123
+ console.log('');
124
+ console.log(chalk.bold(' Daemon Status'));
125
+ console.log(chalk.dim(` Server: ${config.serverUrl}`));
126
+ console.log(chalk.dim(` CWD: ${options.cwd}`));
127
+ console.log(chalk.dim(` Daemon ID: ${daemonId}`));
128
+ console.log(` Auth: ${token ? chalk.green('Token saved') : chalk.yellow('Not authenticated')}`);
129
+ console.log('');
130
+ console.log(chalk.bold(' Permissions'));
131
+ console.log(chalk.dim(` Auto-approve reads: ${config.permissions.autoApproveReads}`));
132
+ console.log(chalk.dim(` Auto-approve writes: ${config.permissions.autoApproveWrites}`));
133
+ console.log(chalk.dim(` Auto-approve bash: ${config.permissions.autoApproveBash}`));
134
+ console.log(chalk.dim(` Blocked paths: ${config.permissions.blockedPaths.join(', ')}`));
135
+ console.log('');
136
+ console.log(chalk.bold(' Limits'));
137
+ console.log(chalk.dim(` Max file read: ${config.limits.maxFileReadSize} bytes`));
138
+ console.log(chalk.dim(` Bash timeout: ${config.limits.bashTimeout}ms`));
139
+ console.log(chalk.dim(` Max concurrent: ${config.limits.maxConcurrentTools}`));
140
+ console.log('');
141
+ });
142
+ program
143
+ .command('config')
144
+ .description('Update daemon configuration')
145
+ .option('-s, --server <url>', 'Set server URL')
146
+ .option('--auto-approve-reads <bool>', 'Auto-approve read operations')
147
+ .option('--auto-approve-writes <bool>', 'Auto-approve write operations')
148
+ .option('--auto-approve-bash <bool>', 'Auto-approve bash commands')
149
+ .action((options) => {
150
+ const config = loadConfig();
151
+ if (options.server) {
152
+ config.serverUrl = options.server;
153
+ }
154
+ if (options.autoApproveReads !== undefined) {
155
+ config.permissions.autoApproveReads = options.autoApproveReads === 'true';
156
+ }
157
+ if (options.autoApproveWrites !== undefined) {
158
+ config.permissions.autoApproveWrites = options.autoApproveWrites === 'true';
159
+ }
160
+ if (options.autoApproveBash !== undefined) {
161
+ config.permissions.autoApproveBash = options.autoApproveBash === 'true';
162
+ }
163
+ saveConfig(config);
164
+ console.log(chalk.green(' Configuration saved.'));
165
+ });
166
+ // Default to 'start' if no command is given
167
+ program.action(async () => {
168
+ // Run start command with defaults
169
+ await program.commands.find((c) => c.name() === 'start')?.parseAsync(['', '', 'start']);
170
+ });
171
+ program.parse();
172
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { type DaemonConfig } from './config.js';
2
+ export type PermissionDecision = 'allow' | 'deny';
3
+ interface ToolRequest {
4
+ toolName: string;
5
+ toolInput: Record<string, unknown>;
6
+ }
7
+ export declare function setSkipPermissions(skip: boolean): void;
8
+ /**
9
+ * Check if a tool request should be allowed or denied.
10
+ *
11
+ * Permission approval now happens in the browser UI via PermissionDialog.
12
+ * By the time a tool request reaches the daemon, the server has already
13
+ * obtained user consent. The daemon only enforces security guardrails
14
+ * (sensitive files, dangerous bash patterns, path traversal).
15
+ */
16
+ export declare function checkPermission(request: ToolRequest, config: DaemonConfig, cwd: string): Promise<PermissionDecision>;
17
+ export {};
@@ -0,0 +1,60 @@
1
+ import path from 'node:path';
2
+ import { isBashBlocked, isSensitivePath, validatePath } from './security.js';
3
+ let skipPermissions = false;
4
+ export function setSkipPermissions(skip) {
5
+ skipPermissions = skip;
6
+ }
7
+ /**
8
+ * Check if a tool request should be allowed or denied.
9
+ *
10
+ * Permission approval now happens in the browser UI via PermissionDialog.
11
+ * By the time a tool request reaches the daemon, the server has already
12
+ * obtained user consent. The daemon only enforces security guardrails
13
+ * (sensitive files, dangerous bash patterns, path traversal).
14
+ */
15
+ export async function checkPermission(request, config, cwd) {
16
+ if (skipPermissions) {
17
+ return 'allow';
18
+ }
19
+ const toolName = request.toolName.toLowerCase();
20
+ const { toolInput } = request;
21
+ // Security: validate file paths stay within cwd
22
+ const filePath = (toolInput.file_path || toolInput.path || '');
23
+ if (filePath) {
24
+ try {
25
+ await validatePath(filePath, cwd);
26
+ }
27
+ catch {
28
+ return 'deny';
29
+ }
30
+ const relativePath = path.relative(cwd, path.resolve(cwd, filePath));
31
+ if (isSensitivePath(relativePath, config.permissions)) {
32
+ return 'deny';
33
+ }
34
+ }
35
+ // Security: block dangerous bash patterns and validate Bash cwd override
36
+ if (toolName === 'bash') {
37
+ const command = (toolInput.command || '');
38
+ const blockReason = isBashBlocked(command);
39
+ if (blockReason) {
40
+ return 'deny';
41
+ }
42
+ // Validate Bash cwd override stays within daemon working directory
43
+ const bashCwd = (toolInput.cwd || '');
44
+ if (bashCwd) {
45
+ try {
46
+ await validatePath(bashCwd, cwd);
47
+ }
48
+ catch {
49
+ return 'deny';
50
+ }
51
+ const relativeBashCwd = path.relative(cwd, path.resolve(cwd, bashCwd));
52
+ if (isSensitivePath(relativeBashCwd, config.permissions)) {
53
+ return 'deny';
54
+ }
55
+ }
56
+ }
57
+ // All other checks pass — server already obtained user consent via browser
58
+ return 'allow';
59
+ }
60
+ //# sourceMappingURL=permissions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions.js","sourceRoot":"","sources":["../src/permissions.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAS7E,IAAI,eAAe,GAAG,KAAK,CAAC;AAE5B,MAAM,UAAU,kBAAkB,CAAC,IAAa;IAC9C,eAAe,GAAG,IAAI,CAAC;AACzB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAAoB,EACpB,MAAoB,EACpB,GAAW;IAEX,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;IAChD,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IAE9B,gDAAgD;IAChD,MAAM,QAAQ,GAAG,CAAC,SAAS,CAAC,SAAS,IAAI,SAAS,CAAC,IAAI,IAAI,EAAE,CAAW,CAAC;IACzE,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,CAAC;YACH,MAAM,YAAY,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACpC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;QACrE,IAAI,eAAe,CAAC,YAAY,EAAE,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC;YACtD,OAAO,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IAED,yEAAyE;IACzE,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QACxB,MAAM,OAAO,GAAG,CAAC,SAAS,CAAC,OAAO,IAAI,EAAE,CAAW,CAAC;QACpD,MAAM,WAAW,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;QAC3C,IAAI,WAAW,EAAE,CAAC;YAChB,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,mEAAmE;QACnE,MAAM,OAAO,GAAG,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,CAAW,CAAC;QAChD,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC;gBACH,MAAM,YAAY,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YACnC,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,MAAM,CAAC;YAChB,CAAC;YAED,MAAM,eAAe,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;YACvE,IAAI,eAAe,CAAC,eAAe,EAAE,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC;gBACzD,OAAO,MAAM,CAAC;YAChB,CAAC;QACH,CAAC;IACH,CAAC;IAED,2EAA2E;IAC3E,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Generate a stable daemon ID based on hostname, username, and cwd.
3
+ * Same project on the same machine always produces the same ID,
4
+ * so reconnections map to the same slot.
5
+ */
6
+ export declare function generateDaemonId(cwd: string): string;
7
+ /**
8
+ * Get a human-readable device name.
9
+ */
10
+ export declare function getDeviceName(): string;
@@ -0,0 +1,23 @@
1
+ import crypto from 'node:crypto';
2
+ import os from 'node:os';
3
+ /**
4
+ * Generate a stable daemon ID based on hostname, username, and cwd.
5
+ * Same project on the same machine always produces the same ID,
6
+ * so reconnections map to the same slot.
7
+ */
8
+ export function generateDaemonId(cwd) {
9
+ const hostname = os.hostname();
10
+ const username = os.userInfo().username;
11
+ const input = `${hostname}:${username}:${cwd}`;
12
+ const hash = crypto.createHash('sha256').update(input).digest('hex').slice(0, 12);
13
+ return `daemon_${hash}`;
14
+ }
15
+ /**
16
+ * Get a human-readable device name.
17
+ */
18
+ export function getDeviceName() {
19
+ const hostname = os.hostname().replace(/\.local$/, '');
20
+ const username = os.userInfo().username;
21
+ return `${username}@${hostname}`;
22
+ }
23
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;IAC/B,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC;IACxC,MAAM,KAAK,GAAG,GAAG,QAAQ,IAAI,QAAQ,IAAI,GAAG,EAAE,CAAC;IAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAClF,OAAO,UAAU,IAAI,EAAE,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC;IACxC,OAAO,GAAG,QAAQ,IAAI,QAAQ,EAAE,CAAC;AACnC,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { type PermissionsConfig } from './config.js';
2
+ /**
3
+ * Validate that a resolved file path stays within the daemon's working directory.
4
+ * Uses realpath to resolve symlinks, preventing symlink escape.
5
+ */
6
+ export declare function validatePath(filePath: string, cwd: string): Promise<string>;
7
+ /**
8
+ * Check if a file path matches any sensitive file patterns.
9
+ */
10
+ export declare function isSensitivePath(filePath: string, config: PermissionsConfig): boolean;
11
+ /**
12
+ * Check if a bash command is blocked.
13
+ */
14
+ export declare function isBashBlocked(command: string): string | null;
15
+ /**
16
+ * Check if a bash command is considered safe.
17
+ */
18
+ export declare function isBashSafe(command: string): boolean;
@@ -0,0 +1,181 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ /**
4
+ * Sensitive file patterns that should never be read or written.
5
+ */
6
+ const SENSITIVE_PATTERNS = [
7
+ /^\.env$/,
8
+ /^\.env\..+$/,
9
+ /\.pem$/,
10
+ /\.key$/,
11
+ /^\.ssh\//,
12
+ /^credentials\./,
13
+ /^\.git\/config$/,
14
+ /^\.npmrc$/,
15
+ /^\.docker\/config\.json$/,
16
+ /id_rsa/,
17
+ /id_ed25519/,
18
+ ];
19
+ /**
20
+ * Bash commands/patterns that are always blocked.
21
+ */
22
+ const BASH_BLOCKLIST = [
23
+ /:\(\)\{\s*:\|:&\s*\};:/, // Fork bomb
24
+ /dd\s+if=\/dev\/zero/, // Disk wipe
25
+ />\s*\/dev\/sd[a-z]/, // Direct device write
26
+ /mkfs\./, // Format filesystem
27
+ /rm\s+-rf\s+\//, // Delete root
28
+ /nc\s+-[el]/, // Reverse shell (netcat listen)
29
+ /bash\s+-i\s+>&\s*\/dev\/tcp/, // Bash reverse shell
30
+ /python.*socket.*connect/, // Python reverse shell
31
+ /curl.*\|\s*bash/, // Pipe curl to bash
32
+ /wget.*\|\s*bash/, // Pipe wget to bash
33
+ /eval\s*\$\(curl/, // Eval remote code
34
+ /chmod\s+[+]?[ugo]*s/, // Setuid/setgid
35
+ /chattr\s+\+i/, // Immutable attribute
36
+ /shutdown|reboot|halt|poweroff/, // System control
37
+ /iptables|ufw/, // Firewall modification
38
+ ];
39
+ /**
40
+ * Bash commands considered safe (auto-approved when configured).
41
+ */
42
+ const SAFE_BASH_COMMANDS = [
43
+ /^ls(\s|$)/,
44
+ /^cat\s/,
45
+ /^head\s/,
46
+ /^tail\s/,
47
+ /^wc\s/,
48
+ /^file\s/,
49
+ /^stat\s/,
50
+ /^which\s/,
51
+ /^type\s/,
52
+ /^echo\s/,
53
+ /^printf\s/,
54
+ /^date(\s|$)/,
55
+ /^whoami(\s|$)/,
56
+ /^pwd(\s|$)/,
57
+ /^env(\s|$)/,
58
+ /^printenv(\s|$)/,
59
+ /^git\s+(status|log|diff|branch|show|rev-parse|remote|tag)/,
60
+ /^node\s+(-v|--version)$/,
61
+ /^npm\s+(ls|list|view|info|outdated|pack\s)/,
62
+ /^rg\s/,
63
+ /^grep\s/,
64
+ /^find\s/,
65
+ /^tree(\s|$)/,
66
+ /^du\s/,
67
+ /^df(\s|$)/,
68
+ /^uname(\s|$)/,
69
+ ];
70
+ /**
71
+ * Check if `child` is contained within `parent` directory.
72
+ * Uses trailing separator to prevent prefix collisions
73
+ * (e.g., /home/user/projects-evil would NOT match /home/user/projects).
74
+ */
75
+ function isContainedIn(child, parent) {
76
+ return child === parent || child.startsWith(parent + path.sep);
77
+ }
78
+ /**
79
+ * Walk up the directory tree from `target` until we find an existing ancestor.
80
+ * Returns the realpath of that ancestor so we can verify containment.
81
+ */
82
+ function findExistingAncestor(target) {
83
+ let current = target;
84
+ // eslint-disable-next-line no-constant-condition
85
+ while (true) {
86
+ if (fs.existsSync(current)) {
87
+ return fs.realpathSync(current);
88
+ }
89
+ const parent = path.dirname(current);
90
+ if (parent === current) {
91
+ // Reached filesystem root — return it
92
+ return parent;
93
+ }
94
+ current = parent;
95
+ }
96
+ }
97
+ /**
98
+ * Validate that a resolved file path stays within the daemon's working directory.
99
+ * Uses realpath to resolve symlinks, preventing symlink escape.
100
+ */
101
+ export async function validatePath(filePath, cwd) {
102
+ const resolved = path.resolve(cwd, filePath);
103
+ // Resolve symlinks in cwd
104
+ let realCwd;
105
+ try {
106
+ realCwd = fs.realpathSync(cwd);
107
+ }
108
+ catch {
109
+ realCwd = cwd;
110
+ }
111
+ // If the file exists, check its real path directly
112
+ if (fs.existsSync(resolved)) {
113
+ const realResolved = fs.realpathSync(resolved);
114
+ if (!isContainedIn(realResolved, realCwd)) {
115
+ throw new Error(`Path escapes working directory: ${filePath}`);
116
+ }
117
+ return realResolved;
118
+ }
119
+ // File doesn't exist — walk up to find the nearest existing ancestor
120
+ // and verify containment. This prevents writes to arbitrary locations
121
+ // when both the file and its immediate parent don't exist.
122
+ const realAncestor = findExistingAncestor(path.dirname(resolved));
123
+ if (!isContainedIn(realAncestor, realCwd)) {
124
+ throw new Error(`Path escapes working directory: ${filePath}`);
125
+ }
126
+ return resolved;
127
+ }
128
+ /**
129
+ * Check if a file path matches any sensitive file patterns.
130
+ */
131
+ export function isSensitivePath(filePath, config) {
132
+ const basename = path.basename(filePath);
133
+ const relativeFromCwd = filePath;
134
+ // Check built-in patterns against both basename and relative path
135
+ for (const pattern of SENSITIVE_PATTERNS) {
136
+ if (pattern.test(basename) || pattern.test(relativeFromCwd)) {
137
+ return true;
138
+ }
139
+ }
140
+ // Check config blocked paths
141
+ for (const blocked of config.blockedPaths) {
142
+ if (matchGlobSimple(blocked, basename) || matchGlobSimple(blocked, relativeFromCwd)) {
143
+ return true;
144
+ }
145
+ }
146
+ return false;
147
+ }
148
+ /**
149
+ * Check if a bash command is blocked.
150
+ */
151
+ export function isBashBlocked(command) {
152
+ const trimmed = command.trim();
153
+ for (const pattern of BASH_BLOCKLIST) {
154
+ if (pattern.test(trimmed)) {
155
+ return `Blocked dangerous command pattern: ${pattern.source}`;
156
+ }
157
+ }
158
+ return null;
159
+ }
160
+ /**
161
+ * Check if a bash command is considered safe.
162
+ */
163
+ export function isBashSafe(command) {
164
+ const trimmed = command.trim();
165
+ return SAFE_BASH_COMMANDS.some((pattern) => pattern.test(trimmed));
166
+ }
167
+ /**
168
+ * Simple glob matching for config patterns.
169
+ * Supports: * (any chars), ** (any path), ? (single char)
170
+ */
171
+ function matchGlobSimple(pattern, filepath) {
172
+ const regexStr = pattern
173
+ .replace(/[.+^${}()|[\]\\]/g, '\\$&')
174
+ .replace(/\*\*/g, '{{DOUBLESTAR}}')
175
+ .replace(/\*/g, '[^/]*')
176
+ .replace(/\?/g, '[^/]')
177
+ .replace(/\{\{DOUBLESTAR\}\}/g, '.*');
178
+ const regex = new RegExp(`^${regexStr}$`);
179
+ return regex.test(filepath);
180
+ }
181
+ //# sourceMappingURL=security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export interface BashInput {
2
+ command: string;
3
+ cwd?: string;
4
+ timeout?: number;
5
+ }
6
+ export interface BashOutput {
7
+ output: string;
8
+ exitCode: number | null;
9
+ timedOut?: boolean;
10
+ }
11
+ /**
12
+ * Execute a bash command using the user's shell.
13
+ * Inherits PATH, HOME, and other environment variables.
14
+ */
15
+ export declare function executeBash(input: BashInput, daemonCwd: string, defaultTimeout: number): Promise<BashOutput>;
@@ -0,0 +1,58 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { validatePath } from '../security.js';
3
+ /**
4
+ * Execute a bash command using the user's shell.
5
+ * Inherits PATH, HOME, and other environment variables.
6
+ */
7
+ export async function executeBash(input, daemonCwd, defaultTimeout) {
8
+ const shell = process.env.SHELL || '/bin/bash';
9
+ const timeout = input.timeout || defaultTimeout;
10
+ // Validate cwd if provided
11
+ let cwd = daemonCwd;
12
+ if (input.cwd) {
13
+ cwd = await validatePath(input.cwd, daemonCwd);
14
+ }
15
+ return new Promise((resolve) => {
16
+ const chunks = [];
17
+ let timedOut = false;
18
+ const child = spawn(shell, ['-c', input.command], {
19
+ cwd,
20
+ env: { ...process.env },
21
+ stdio: ['ignore', 'pipe', 'pipe'],
22
+ });
23
+ const timer = setTimeout(() => {
24
+ timedOut = true;
25
+ child.kill('SIGTERM');
26
+ // Force kill after 5s grace period
27
+ setTimeout(() => {
28
+ if (!child.killed) {
29
+ child.kill('SIGKILL');
30
+ }
31
+ }, 5000);
32
+ }, timeout);
33
+ child.stdout.on('data', (data) => chunks.push(data));
34
+ child.stderr.on('data', (data) => chunks.push(data));
35
+ child.on('close', (code) => {
36
+ clearTimeout(timer);
37
+ const output = Buffer.concat(chunks).toString('utf-8');
38
+ // Cap output to 1MB
39
+ const maxOutput = 1024 * 1024;
40
+ const truncated = output.length > maxOutput
41
+ ? output.slice(0, maxOutput) + '\n[output truncated at 1MB]'
42
+ : output;
43
+ resolve({
44
+ output: truncated,
45
+ exitCode: code,
46
+ ...(timedOut && { timedOut: true }),
47
+ });
48
+ });
49
+ child.on('error', (err) => {
50
+ clearTimeout(timer);
51
+ resolve({
52
+ output: `Error: ${err.message}`,
53
+ exitCode: 1,
54
+ });
55
+ });
56
+ });
57
+ }
58
+ //# sourceMappingURL=bash.js.map