@naarang/ccc 1.0.11 → 1.0.13

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.
@@ -123,6 +123,68 @@ function getPermissionModeForSession(sessionId) {
123
123
  }
124
124
  }
125
125
 
126
+ /**
127
+ * Reads the current working directory for a session from session-config.json
128
+ * Returns the cwd or null if not found
129
+ */
130
+ function getCwdForSession(sessionId) {
131
+ try {
132
+ if (!fs.existsSync(SESSION_CONFIG_FILE)) {
133
+ log('Session config file not found, no cwd available', { path: SESSION_CONFIG_FILE });
134
+ return null;
135
+ }
136
+
137
+ const data = fs.readFileSync(SESSION_CONFIG_FILE, 'utf8');
138
+ const config = JSON.parse(data);
139
+
140
+ if (config[sessionId] && config[sessionId].cwd) {
141
+ const cwd = config[sessionId].cwd;
142
+ log('Found cwd for session', { sessionId, cwd });
143
+ return cwd;
144
+ }
145
+
146
+ log('No cwd found for session', { sessionId });
147
+ return null;
148
+
149
+ } catch (error) {
150
+ log('Error reading cwd from session config', { error: error.message });
151
+ return null;
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Checks if a file path is outside the project's current working directory
157
+ * Returns true if the file is outside the project directory
158
+ */
159
+ function isFileOutsideProjectDirectory(filePath, projectCwd) {
160
+ try {
161
+ if (!filePath || !projectCwd) {
162
+ return false;
163
+ }
164
+
165
+ // Resolve both paths to absolute paths
166
+ const absoluteFilePath = path.resolve(filePath);
167
+ const absoluteProjectCwd = path.resolve(projectCwd);
168
+
169
+ // Check if the file path starts with the project cwd
170
+ const isInside = absoluteFilePath.startsWith(absoluteProjectCwd + path.sep) ||
171
+ absoluteFilePath === absoluteProjectCwd;
172
+
173
+ log('Checking if file is outside project directory', {
174
+ filePath: absoluteFilePath,
175
+ projectCwd: absoluteProjectCwd,
176
+ isOutside: !isInside
177
+ });
178
+
179
+ return !isInside;
180
+
181
+ } catch (error) {
182
+ log('Error checking file path', { error: error.message });
183
+ // On error, be conservative and ask for permission
184
+ return true;
185
+ }
186
+ }
187
+
126
188
  /**
127
189
  * Reads JSON input from stdin
128
190
  */
@@ -537,6 +599,26 @@ async function main() {
537
599
  // For now, ask user normally
538
600
  }
539
601
 
602
+ // Special handling for Read tool - check if file is outside project directory
603
+ if (toolName === 'Read') {
604
+ const projectCwd = getCwdForSession(hookInput.session_id);
605
+ const filePath = hookInput.tool_input?.file_path;
606
+
607
+ if (projectCwd && filePath) {
608
+ const isOutside = isFileOutsideProjectDirectory(filePath, projectCwd);
609
+
610
+ if (!isOutside) {
611
+ // File is inside project directory, auto-approve
612
+ log('Auto-approving Read (file inside project directory)', { filePath, projectCwd });
613
+ outputDecision('allow', 'File is within project directory');
614
+ process.exit(0);
615
+ } else {
616
+ // File is outside project directory, will ask user below
617
+ log('Read operation outside project directory, will ask user', { filePath, projectCwd });
618
+ }
619
+ }
620
+ }
621
+
540
622
  // Check if this specific tool+command is in allowed list
541
623
  if (checkAllowedTools(toolName, hookInput.tool_input)) {
542
624
  log('Auto-approving (found in allowed list)');