chatcc-agent 0.3.8 → 0.3.9

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chatcc-agent",
3
- "version": "0.3.8",
3
+ "version": "0.3.9",
4
4
  "description": "CCLink Agent - bridges Claude Code CLI with instant messaging",
5
5
  "bin": {
6
6
  "chatcc": "src/cli.js"
@@ -361,6 +361,57 @@ class FileService {
361
361
  }
362
362
  }
363
363
 
364
+ async handleMkdirRequest(from, data, sessionConstraint) {
365
+ const { request_id, path: parentPath, name } = data;
366
+
367
+ // Validate name
368
+ if (!name || typeof name !== 'string' || name.length > 255 ||
369
+ name.includes('/') || name.includes('\0') ||
370
+ name === '.' || name === '..') {
371
+ await this._reply(from, 'file_mkdir_response', {
372
+ request_id,
373
+ error: 'Invalid folder name',
374
+ });
375
+ return;
376
+ }
377
+
378
+ const resolved = resolvePath(parentPath);
379
+ if (!resolved) {
380
+ await this._reply(from, 'file_mkdir_response', { request_id, error: 'Invalid parent path' });
381
+ return;
382
+ }
383
+
384
+ const safePath = await this.checkPermission(from, resolved, 'mkdir', sessionConstraint);
385
+ if (!safePath) {
386
+ await this._reply(from, 'file_mkdir_response', { request_id, error: 'Access denied' });
387
+ return;
388
+ }
389
+
390
+ try {
391
+ const fullPath = path.join(safePath, name);
392
+
393
+ // Use lstatSync (no symlink follow) to detect existing entries including dangling symlinks
394
+ try {
395
+ const stat = fs.lstatSync(fullPath);
396
+ // Something already exists at this path (file, dir, or symlink)
397
+ await this._reply(from, 'file_mkdir_response', { request_id, error: 'Already exists' });
398
+ return;
399
+ } catch {
400
+ // Path does not exist — safe to create
401
+ }
402
+
403
+ fs.mkdirSync(fullPath, { recursive: false });
404
+ console.log(`[FileService] mkdir: ${fullPath} (by ${from})`);
405
+ await this._reply(from, 'file_mkdir_response', {
406
+ request_id,
407
+ path: fullPath,
408
+ name,
409
+ });
410
+ } catch (e) {
411
+ await this._reply(from, 'file_mkdir_response', { request_id, error: e.message });
412
+ }
413
+ }
414
+
364
415
  async handleSearchRequest(from, data, sessionConstraint) {
365
416
  const { request_id, pattern, path: searchPath } = data;
366
417
  const resolved = resolvePath(searchPath);
package/src/index.js CHANGED
@@ -398,6 +398,12 @@ async function main() {
398
398
  break;
399
399
  }
400
400
 
401
+ case 'file_mkdir_request': {
402
+ const fsConstraint = resolveFileConstraint(data);
403
+ fileService.handleMkdirRequest(from, data, fsConstraint);
404
+ break;
405
+ }
406
+
401
407
  case 'session_create':
402
408
  handleSessionCreate(imClient, from, data, sessions);
403
409
  break;