@helmisatria/mcp-chrome-bridge 1.0.30

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 (129) hide show
  1. package/README.md +183 -0
  2. package/dist/README.md +25 -0
  3. package/dist/agent/attachment-service.d.ts +83 -0
  4. package/dist/agent/attachment-service.js +370 -0
  5. package/dist/agent/attachment-service.js.map +1 -0
  6. package/dist/agent/ccr-detector.d.ts +59 -0
  7. package/dist/agent/ccr-detector.js +311 -0
  8. package/dist/agent/ccr-detector.js.map +1 -0
  9. package/dist/agent/chat-service.d.ts +50 -0
  10. package/dist/agent/chat-service.js +439 -0
  11. package/dist/agent/chat-service.js.map +1 -0
  12. package/dist/agent/db/client.d.ts +26 -0
  13. package/dist/agent/db/client.js +244 -0
  14. package/dist/agent/db/client.js.map +1 -0
  15. package/dist/agent/db/index.d.ts +5 -0
  16. package/dist/agent/db/index.js +22 -0
  17. package/dist/agent/db/index.js.map +1 -0
  18. package/dist/agent/db/schema.d.ts +711 -0
  19. package/dist/agent/db/schema.js +121 -0
  20. package/dist/agent/db/schema.js.map +1 -0
  21. package/dist/agent/directory-picker.d.ts +11 -0
  22. package/dist/agent/directory-picker.js +149 -0
  23. package/dist/agent/directory-picker.js.map +1 -0
  24. package/dist/agent/engines/claude.d.ts +79 -0
  25. package/dist/agent/engines/claude.js +1338 -0
  26. package/dist/agent/engines/claude.js.map +1 -0
  27. package/dist/agent/engines/codex.d.ts +48 -0
  28. package/dist/agent/engines/codex.js +822 -0
  29. package/dist/agent/engines/codex.js.map +1 -0
  30. package/dist/agent/engines/types.d.ts +133 -0
  31. package/dist/agent/engines/types.js +3 -0
  32. package/dist/agent/engines/types.js.map +1 -0
  33. package/dist/agent/message-service.d.ts +56 -0
  34. package/dist/agent/message-service.js +198 -0
  35. package/dist/agent/message-service.js.map +1 -0
  36. package/dist/agent/open-project.d.ts +25 -0
  37. package/dist/agent/open-project.js +469 -0
  38. package/dist/agent/open-project.js.map +1 -0
  39. package/dist/agent/project-service.d.ts +49 -0
  40. package/dist/agent/project-service.js +254 -0
  41. package/dist/agent/project-service.js.map +1 -0
  42. package/dist/agent/project-types.d.ts +27 -0
  43. package/dist/agent/project-types.js +3 -0
  44. package/dist/agent/project-types.js.map +1 -0
  45. package/dist/agent/session-service.d.ts +198 -0
  46. package/dist/agent/session-service.js +292 -0
  47. package/dist/agent/session-service.js.map +1 -0
  48. package/dist/agent/storage.d.ts +27 -0
  49. package/dist/agent/storage.js +73 -0
  50. package/dist/agent/storage.js.map +1 -0
  51. package/dist/agent/stream-manager.d.ts +42 -0
  52. package/dist/agent/stream-manager.js +243 -0
  53. package/dist/agent/stream-manager.js.map +1 -0
  54. package/dist/agent/tool-bridge.d.ts +44 -0
  55. package/dist/agent/tool-bridge.js +50 -0
  56. package/dist/agent/tool-bridge.js.map +1 -0
  57. package/dist/agent/types.d.ts +6 -0
  58. package/dist/agent/types.js +3 -0
  59. package/dist/agent/types.js.map +1 -0
  60. package/dist/cli.d.ts +2 -0
  61. package/dist/cli.js +224 -0
  62. package/dist/cli.js.map +1 -0
  63. package/dist/constant/index.d.ts +60 -0
  64. package/dist/constant/index.js +80 -0
  65. package/dist/constant/index.js.map +1 -0
  66. package/dist/file-handler.d.ts +41 -0
  67. package/dist/file-handler.js +295 -0
  68. package/dist/file-handler.js.map +1 -0
  69. package/dist/index.d.ts +2 -0
  70. package/dist/index.js +35 -0
  71. package/dist/index.js.map +1 -0
  72. package/dist/mcp/mcp-server-stdio.d.ts +72 -0
  73. package/dist/mcp/mcp-server-stdio.js +143 -0
  74. package/dist/mcp/mcp-server-stdio.js.map +1 -0
  75. package/dist/mcp/mcp-server.d.ts +36 -0
  76. package/dist/mcp/mcp-server.js +26 -0
  77. package/dist/mcp/mcp-server.js.map +1 -0
  78. package/dist/mcp/register-tools.d.ts +2 -0
  79. package/dist/mcp/register-tools.js +148 -0
  80. package/dist/mcp/register-tools.js.map +1 -0
  81. package/dist/mcp/stdio-config.json +3 -0
  82. package/dist/native-messaging-host.d.ts +42 -0
  83. package/dist/native-messaging-host.js +312 -0
  84. package/dist/native-messaging-host.js.map +1 -0
  85. package/dist/run_host.bat +194 -0
  86. package/dist/run_host.sh +264 -0
  87. package/dist/scripts/browser-config.d.ts +28 -0
  88. package/dist/scripts/browser-config.js +229 -0
  89. package/dist/scripts/browser-config.js.map +1 -0
  90. package/dist/scripts/build.d.ts +1 -0
  91. package/dist/scripts/build.js +126 -0
  92. package/dist/scripts/build.js.map +1 -0
  93. package/dist/scripts/constant.d.ts +4 -0
  94. package/dist/scripts/constant.js +8 -0
  95. package/dist/scripts/constant.js.map +1 -0
  96. package/dist/scripts/doctor.d.ts +70 -0
  97. package/dist/scripts/doctor.js +930 -0
  98. package/dist/scripts/doctor.js.map +1 -0
  99. package/dist/scripts/postinstall.d.ts +2 -0
  100. package/dist/scripts/postinstall.js +246 -0
  101. package/dist/scripts/postinstall.js.map +1 -0
  102. package/dist/scripts/register-dev.d.ts +1 -0
  103. package/dist/scripts/register-dev.js +5 -0
  104. package/dist/scripts/register-dev.js.map +1 -0
  105. package/dist/scripts/register.d.ts +2 -0
  106. package/dist/scripts/register.js +28 -0
  107. package/dist/scripts/register.js.map +1 -0
  108. package/dist/scripts/report.d.ts +96 -0
  109. package/dist/scripts/report.js +686 -0
  110. package/dist/scripts/report.js.map +1 -0
  111. package/dist/scripts/utils.d.ts +64 -0
  112. package/dist/scripts/utils.js +443 -0
  113. package/dist/scripts/utils.js.map +1 -0
  114. package/dist/server/index.d.ts +35 -0
  115. package/dist/server/index.js +312 -0
  116. package/dist/server/index.js.map +1 -0
  117. package/dist/server/routes/agent.d.ts +21 -0
  118. package/dist/server/routes/agent.js +971 -0
  119. package/dist/server/routes/agent.js.map +1 -0
  120. package/dist/server/routes/index.d.ts +4 -0
  121. package/dist/server/routes/index.js +9 -0
  122. package/dist/server/routes/index.js.map +1 -0
  123. package/dist/trace-analyzer.d.ts +14 -0
  124. package/dist/trace-analyzer.js +113 -0
  125. package/dist/trace-analyzer.js.map +1 -0
  126. package/dist/util/logger.d.ts +1 -0
  127. package/dist/util/logger.js +43 -0
  128. package/dist/util/logger.js.map +1 -0
  129. package/package.json +91 -0
package/README.md ADDED
@@ -0,0 +1,183 @@
1
+ # Fastify Chrome Native Messaging服务
2
+
3
+ 这是一个基于Fastify的TypeScript项目,用于与Chrome扩展进行原生通信。
4
+
5
+ ## 功能特性
6
+
7
+ - 通过Chrome Native Messaging协议与Chrome扩展进行双向通信
8
+ - **支持多浏览器**: Chrome 和 Chromium (包括 Linux、macOS 和 Windows)
9
+ - 提供RESTful API服务
10
+ - 完全使用TypeScript开发
11
+ - 包含完整的测试套件
12
+ - 遵循代码质量最佳实践
13
+
14
+ ## 开发环境设置
15
+
16
+ ### 前置条件
17
+
18
+ - Node.js 20+
19
+ - npm 8+ 或 pnpm 8+
20
+
21
+ ### 安装
22
+
23
+ ```bash
24
+ git clone https://github.com/your-username/fastify-chrome-native.git
25
+ cd fastify-chrome-native
26
+ npm install
27
+ ```
28
+
29
+ ### 开发
30
+
31
+ 1. 本地构建注册native server
32
+
33
+ ```bash
34
+ cd app/native-server
35
+ npm run dev
36
+ ```
37
+
38
+ 2. 启动chrome extension
39
+
40
+ ```bash
41
+ cd app/chrome-extension
42
+ npm run dev
43
+ ```
44
+
45
+ ### 构建
46
+
47
+ ```bash
48
+ npm run build
49
+ ```
50
+
51
+ ### 注册Native Messaging主机
52
+
53
+ #### 自动检测并注册所有已安装的浏览器
54
+
55
+ ```bash
56
+ mcp-chrome-bridge register --detect
57
+ ```
58
+
59
+ #### 注册特定浏览器
60
+
61
+ ```bash
62
+ # 仅注册 Chrome
63
+ mcp-chrome-bridge register --browser chrome
64
+
65
+ # 仅注册 Chromium
66
+ mcp-chrome-bridge register --browser chromium
67
+
68
+ # 注册所有支持的浏览器
69
+ mcp-chrome-bridge register --browser all
70
+ ```
71
+
72
+ #### 全局安装(会自动注册检测到的浏览器)
73
+
74
+ ```bash
75
+ npm i -g mcp-chrome-bridge
76
+ ```
77
+
78
+ #### 浏览器支持
79
+
80
+ | 浏览器 | Linux | macOS | Windows |
81
+ | ------------- | ----- | ----- | ------- |
82
+ | Google Chrome | ✓ | ✓ | ✓ |
83
+ | Chromium | ✓ | ✓ | ✓ |
84
+
85
+ 注册位置:
86
+
87
+ - **Linux**: `~/.config/[browser-name]/NativeMessagingHosts/`
88
+ - **macOS**: `~/Library/Application Support/[Browser]/NativeMessagingHosts/`
89
+ - **Windows**: `%APPDATA%\[Browser]\NativeMessagingHosts\`
90
+
91
+ ### 与Chrome扩展集成
92
+
93
+ 以下是Chrome扩展中如何使用此服务的简单示例:
94
+
95
+ ```javascript
96
+ // background.js
97
+ let nativePort = null;
98
+ let serverRunning = false;
99
+
100
+ // 启动Native Messaging服务
101
+ function startServer() {
102
+ if (nativePort) {
103
+ console.log('已连接到Native Messaging主机');
104
+ return;
105
+ }
106
+
107
+ try {
108
+ nativePort = chrome.runtime.connectNative('com.yourcompany.fastify_native_host');
109
+
110
+ nativePort.onMessage.addListener((message) => {
111
+ console.log('收到Native消息:', message);
112
+
113
+ if (message.type === 'started') {
114
+ serverRunning = true;
115
+ console.log(`服务已启动,端口: ${message.payload.port}`);
116
+ } else if (message.type === 'stopped') {
117
+ serverRunning = false;
118
+ console.log('服务已停止');
119
+ } else if (message.type === 'error') {
120
+ console.error('Native错误:', message.payload.message);
121
+ }
122
+ });
123
+
124
+ nativePort.onDisconnect.addListener(() => {
125
+ console.log('Native连接断开:', chrome.runtime.lastError);
126
+ nativePort = null;
127
+ serverRunning = false;
128
+ });
129
+
130
+ // 启动服务器
131
+ nativePort.postMessage({ type: 'start', payload: { port: 3000 } });
132
+ } catch (error) {
133
+ console.error('启动Native Messaging时出错:', error);
134
+ }
135
+ }
136
+
137
+ // 停止服务器
138
+ function stopServer() {
139
+ if (nativePort && serverRunning) {
140
+ nativePort.postMessage({ type: 'stop' });
141
+ }
142
+ }
143
+
144
+ // 测试与服务器的通信
145
+ async function testPing() {
146
+ try {
147
+ const response = await fetch('http://localhost:3000/ping');
148
+ const data = await response.json();
149
+ console.log('Ping响应:', data);
150
+ return data;
151
+ } catch (error) {
152
+ console.error('Ping失败:', error);
153
+ return null;
154
+ }
155
+ }
156
+
157
+ // 在扩展启动时连接Native主机
158
+ chrome.runtime.onStartup.addListener(startServer);
159
+
160
+ // 导出供popup或内容脚本使用的API
161
+ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
162
+ if (message.action === 'startServer') {
163
+ startServer();
164
+ sendResponse({ success: true });
165
+ } else if (message.action === 'stopServer') {
166
+ stopServer();
167
+ sendResponse({ success: true });
168
+ } else if (message.action === 'testPing') {
169
+ testPing().then(sendResponse);
170
+ return true; // 指示我们将异步发送响应
171
+ }
172
+ });
173
+ ```
174
+
175
+ ### 测试
176
+
177
+ ```bash
178
+ npm run test
179
+ ```
180
+
181
+ ### 许可证
182
+
183
+ MIT
package/dist/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # @helmisatria/mcp-chrome
2
+
3
+ 本程序为Chrome扩展的Native Messaging主机端。
4
+
5
+ ## 安装说明
6
+
7
+ 1. 确保已安装Node.js
8
+ 2. 全局安装本程序:
9
+ ```
10
+ npm install -g @helmisatria/mcp-chrome
11
+ ```
12
+ 3. 注册Native Messaging主机:
13
+ ```
14
+ # 用户级别安装(推荐)
15
+ @helmisatria/mcp-chrome register
16
+
17
+ # 如果用户级别安装失败,可以尝试系统级别安装
18
+ @helmisatria/mcp-chrome register --system
19
+ # 或者使用管理员权限
20
+ sudo @helmisatria/mcp-chrome register
21
+ ```
22
+
23
+ ## 使用方法
24
+
25
+ 此应用程序由Chrome扩展自动启动,无需手动运行。
@@ -0,0 +1,83 @@
1
+ import type { AgentAttachment, AttachmentMetadata, AttachmentProjectStats } from 'chrome-mcp-shared';
2
+ export interface SaveAttachmentInput {
3
+ projectId: string;
4
+ messageId: string;
5
+ attachment: AgentAttachment;
6
+ index: number;
7
+ }
8
+ export interface SavedAttachment {
9
+ /** Absolute path on disk (for engines) */
10
+ absolutePath: string;
11
+ /** Persisted filename under project dir */
12
+ filename: string;
13
+ /** Metadata to store in message.metadata.attachments */
14
+ metadata: AttachmentMetadata;
15
+ }
16
+ export interface AttachmentStats {
17
+ rootDir: string;
18
+ totalFiles: number;
19
+ totalBytes: number;
20
+ projects: AttachmentProjectStats[];
21
+ }
22
+ export interface CleanupAttachmentsInput {
23
+ /** If omitted, cleanup all project dirs under root */
24
+ projectIds?: string[];
25
+ }
26
+ export interface CleanupProjectResult {
27
+ projectId: string;
28
+ dirPath: string;
29
+ existed: boolean;
30
+ removedFiles: number;
31
+ removedBytes: number;
32
+ }
33
+ export interface CleanupResult {
34
+ rootDir: string;
35
+ removedFiles: number;
36
+ removedBytes: number;
37
+ results: CleanupProjectResult[];
38
+ }
39
+ export declare class AttachmentService {
40
+ /**
41
+ * Get the root directory for all attachments.
42
+ */
43
+ getAttachmentsRootDir(): string;
44
+ /**
45
+ * Get the directory for a specific project's attachments.
46
+ */
47
+ getProjectAttachmentsDir(projectId: string): string;
48
+ /**
49
+ * Get the absolute path for a specific attachment file.
50
+ * Validates to prevent path traversal attacks.
51
+ */
52
+ getAttachmentPath(projectId: string, filename: string): string;
53
+ /**
54
+ * Save an attachment to persistent storage.
55
+ * Creates directories if needed.
56
+ */
57
+ saveAttachment(input: SaveAttachmentInput): Promise<SavedAttachment>;
58
+ /**
59
+ * Get statistics for all attachments.
60
+ */
61
+ getAttachmentStats(): Promise<AttachmentStats>;
62
+ /**
63
+ * Get statistics for a single project.
64
+ */
65
+ private getProjectStats;
66
+ /**
67
+ * Cleanup attachments for specified projects or all projects.
68
+ */
69
+ cleanupAttachments(input?: CleanupAttachmentsInput): Promise<CleanupResult>;
70
+ /**
71
+ * Cleanup attachments for a single project.
72
+ */
73
+ private cleanupProject;
74
+ /**
75
+ * Check if an attachment file exists.
76
+ */
77
+ attachmentExists(projectId: string, filename: string): Promise<boolean>;
78
+ /**
79
+ * Read an attachment file.
80
+ */
81
+ readAttachment(projectId: string, filename: string): Promise<Buffer>;
82
+ }
83
+ export declare const attachmentService: AttachmentService;
@@ -0,0 +1,370 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.attachmentService = exports.AttachmentService = void 0;
7
+ /**
8
+ * Attachment Service for persisting and managing image attachments.
9
+ *
10
+ * Handles:
11
+ * - Saving attachments to persistent storage (not temp files)
12
+ * - Getting attachment statistics per project
13
+ * - Cleaning up attachments by project or all
14
+ *
15
+ * Storage structure:
16
+ * ~/.chrome-mcp-agent/attachments/{projectId}/{messageId}-{index}-{uuid}.{ext}
17
+ */
18
+ const promises_1 = __importDefault(require("node:fs/promises"));
19
+ const node_path_1 = __importDefault(require("node:path"));
20
+ const node_crypto_1 = require("node:crypto");
21
+ const storage_1 = require("./storage");
22
+ // ============================================================
23
+ // Constants
24
+ // ============================================================
25
+ const ATTACHMENTS_DIR_NAME = 'attachments';
26
+ /** Allowed MIME types for image attachments */
27
+ const ALLOWED_MIME_TYPES = new Set(['image/png', 'image/jpeg', 'image/gif', 'image/webp']);
28
+ // ============================================================
29
+ // Helper Functions
30
+ // ============================================================
31
+ /**
32
+ * Convert MIME type to file extension.
33
+ */
34
+ function mimeTypeToExt(mimeType) {
35
+ switch (mimeType) {
36
+ case 'image/png':
37
+ return 'png';
38
+ case 'image/jpeg':
39
+ return 'jpg';
40
+ case 'image/gif':
41
+ return 'gif';
42
+ case 'image/webp':
43
+ return 'webp';
44
+ default:
45
+ return 'bin';
46
+ }
47
+ }
48
+ /**
49
+ * Build a unique filename for an attachment.
50
+ * Format: {messageId}-{index}-{uuid}.{ext}
51
+ */
52
+ function buildAttachmentFilename(params) {
53
+ const ext = mimeTypeToExt(params.mimeType);
54
+ const uuid = (0, node_crypto_1.randomUUID)().slice(0, 8);
55
+ return `${params.messageId}-${params.index}-${uuid}.${ext}`;
56
+ }
57
+ /**
58
+ * Validate filename to prevent path traversal attacks.
59
+ */
60
+ function isValidFilename(filename) {
61
+ // Reject empty, path separators, parent directory references
62
+ if (!filename || filename.includes('/') || filename.includes('\\')) {
63
+ return false;
64
+ }
65
+ if (filename === '.' || filename === '..' || filename.startsWith('.')) {
66
+ return false;
67
+ }
68
+ // Only allow alphanumeric, dash, underscore, dot
69
+ return /^[a-zA-Z0-9_-]+\.[a-zA-Z0-9]+$/.test(filename);
70
+ }
71
+ /**
72
+ * Validate projectId to prevent path traversal attacks.
73
+ */
74
+ function isValidProjectId(projectId) {
75
+ if (!projectId)
76
+ return false;
77
+ // UUID format or alphanumeric with dashes
78
+ return /^[a-zA-Z0-9_-]+$/.test(projectId);
79
+ }
80
+ // ============================================================
81
+ // AttachmentService Class
82
+ // ============================================================
83
+ class AttachmentService {
84
+ /**
85
+ * Get the root directory for all attachments.
86
+ */
87
+ getAttachmentsRootDir() {
88
+ return node_path_1.default.join((0, storage_1.getAgentDataDir)(), ATTACHMENTS_DIR_NAME);
89
+ }
90
+ /**
91
+ * Get the directory for a specific project's attachments.
92
+ */
93
+ getProjectAttachmentsDir(projectId) {
94
+ if (!isValidProjectId(projectId)) {
95
+ throw new Error(`Invalid projectId: ${projectId}`);
96
+ }
97
+ return node_path_1.default.join(this.getAttachmentsRootDir(), projectId);
98
+ }
99
+ /**
100
+ * Get the absolute path for a specific attachment file.
101
+ * Validates to prevent path traversal attacks.
102
+ */
103
+ getAttachmentPath(projectId, filename) {
104
+ if (!isValidProjectId(projectId)) {
105
+ throw new Error(`Invalid projectId: ${projectId}`);
106
+ }
107
+ if (!isValidFilename(filename)) {
108
+ throw new Error(`Invalid filename: ${filename}`);
109
+ }
110
+ const projectDir = this.getProjectAttachmentsDir(projectId);
111
+ const filePath = node_path_1.default.join(projectDir, filename);
112
+ // Double-check resolved path is within project directory (defense in depth)
113
+ const resolved = node_path_1.default.resolve(filePath);
114
+ const resolvedProjectDir = node_path_1.default.resolve(projectDir);
115
+ if (!resolved.startsWith(resolvedProjectDir + node_path_1.default.sep)) {
116
+ throw new Error('Path traversal attempt detected');
117
+ }
118
+ return filePath;
119
+ }
120
+ /**
121
+ * Save an attachment to persistent storage.
122
+ * Creates directories if needed.
123
+ */
124
+ async saveAttachment(input) {
125
+ const { projectId, messageId, attachment, index } = input;
126
+ // Validate input
127
+ if (!isValidProjectId(projectId)) {
128
+ throw new Error(`Invalid projectId: ${projectId}`);
129
+ }
130
+ if (attachment.type !== 'image') {
131
+ throw new Error(`Unsupported attachment type: ${attachment.type}`);
132
+ }
133
+ if (!ALLOWED_MIME_TYPES.has(attachment.mimeType)) {
134
+ throw new Error(`Unsupported MIME type: ${attachment.mimeType}`);
135
+ }
136
+ // Build filename and paths
137
+ const filename = buildAttachmentFilename({
138
+ messageId,
139
+ index,
140
+ mimeType: attachment.mimeType,
141
+ });
142
+ const projectDir = this.getProjectAttachmentsDir(projectId);
143
+ const absolutePath = node_path_1.default.join(projectDir, filename);
144
+ // Decode base64 and get size
145
+ const buffer = Buffer.from(attachment.dataBase64, 'base64');
146
+ const sizeBytes = buffer.length;
147
+ // Create directory and write file
148
+ await promises_1.default.mkdir(projectDir, { recursive: true });
149
+ await promises_1.default.writeFile(absolutePath, buffer);
150
+ // Build metadata
151
+ const metadata = {
152
+ version: 1,
153
+ kind: 'image',
154
+ projectId,
155
+ messageId,
156
+ index,
157
+ filename,
158
+ urlPath: `/agent/attachments/${projectId}/${filename}`,
159
+ mimeType: attachment.mimeType,
160
+ sizeBytes,
161
+ originalName: attachment.name,
162
+ createdAt: new Date().toISOString(),
163
+ };
164
+ console.error(`[AttachmentService] Saved attachment: ${absolutePath} (${sizeBytes} bytes)`);
165
+ return {
166
+ absolutePath,
167
+ filename,
168
+ metadata,
169
+ };
170
+ }
171
+ /**
172
+ * Get statistics for all attachments.
173
+ */
174
+ async getAttachmentStats() {
175
+ const rootDir = this.getAttachmentsRootDir();
176
+ const projects = [];
177
+ let totalFiles = 0;
178
+ let totalBytes = 0;
179
+ try {
180
+ // Check if root directory exists
181
+ await promises_1.default.access(rootDir);
182
+ // Read all project directories
183
+ const entries = await promises_1.default.readdir(rootDir, { withFileTypes: true });
184
+ for (const entry of entries) {
185
+ if (!entry.isDirectory())
186
+ continue;
187
+ const projectId = entry.name;
188
+ const dirPath = node_path_1.default.join(rootDir, projectId);
189
+ try {
190
+ const stats = await this.getProjectStats(projectId, dirPath);
191
+ projects.push(stats);
192
+ totalFiles += stats.fileCount;
193
+ totalBytes += stats.totalBytes;
194
+ }
195
+ catch (error) {
196
+ // Skip directories we can't read
197
+ console.error(`[AttachmentService] Failed to stat project ${projectId}:`, error);
198
+ }
199
+ }
200
+ }
201
+ catch (_a) {
202
+ // Root directory doesn't exist - return empty stats
203
+ }
204
+ return {
205
+ rootDir,
206
+ totalFiles,
207
+ totalBytes,
208
+ projects,
209
+ };
210
+ }
211
+ /**
212
+ * Get statistics for a single project.
213
+ */
214
+ async getProjectStats(projectId, dirPath) {
215
+ let fileCount = 0;
216
+ let totalBytes = 0;
217
+ let lastModifiedAt;
218
+ let latestMtime = 0;
219
+ try {
220
+ const files = await promises_1.default.readdir(dirPath);
221
+ for (const file of files) {
222
+ const filePath = node_path_1.default.join(dirPath, file);
223
+ try {
224
+ const stat = await promises_1.default.stat(filePath);
225
+ if (stat.isFile()) {
226
+ fileCount++;
227
+ totalBytes += stat.size;
228
+ if (stat.mtimeMs > latestMtime) {
229
+ latestMtime = stat.mtimeMs;
230
+ lastModifiedAt = stat.mtime.toISOString();
231
+ }
232
+ }
233
+ }
234
+ catch (_a) {
235
+ // Skip files we can't stat
236
+ }
237
+ }
238
+ return {
239
+ projectId,
240
+ dirPath,
241
+ exists: true,
242
+ fileCount,
243
+ totalBytes,
244
+ lastModifiedAt,
245
+ };
246
+ }
247
+ catch (_b) {
248
+ return {
249
+ projectId,
250
+ dirPath,
251
+ exists: false,
252
+ fileCount: 0,
253
+ totalBytes: 0,
254
+ };
255
+ }
256
+ }
257
+ /**
258
+ * Cleanup attachments for specified projects or all projects.
259
+ */
260
+ async cleanupAttachments(input) {
261
+ const rootDir = this.getAttachmentsRootDir();
262
+ const results = [];
263
+ let totalRemovedFiles = 0;
264
+ let totalRemovedBytes = 0;
265
+ // Determine which projects to clean
266
+ let projectIds;
267
+ if ((input === null || input === void 0 ? void 0 : input.projectIds) && input.projectIds.length > 0) {
268
+ // Clean specific projects
269
+ projectIds = input.projectIds;
270
+ }
271
+ else {
272
+ // Clean all projects - enumerate from filesystem
273
+ try {
274
+ const entries = await promises_1.default.readdir(rootDir, { withFileTypes: true });
275
+ projectIds = entries.filter((e) => e.isDirectory()).map((e) => e.name);
276
+ }
277
+ catch (_a) {
278
+ // Root doesn't exist - nothing to clean
279
+ return {
280
+ rootDir,
281
+ removedFiles: 0,
282
+ removedBytes: 0,
283
+ results: [],
284
+ };
285
+ }
286
+ }
287
+ // Clean each project
288
+ for (const projectId of projectIds) {
289
+ if (!isValidProjectId(projectId)) {
290
+ console.error(`[AttachmentService] Skipping invalid projectId: ${projectId}`);
291
+ continue;
292
+ }
293
+ const result = await this.cleanupProject(projectId);
294
+ results.push(result);
295
+ totalRemovedFiles += result.removedFiles;
296
+ totalRemovedBytes += result.removedBytes;
297
+ }
298
+ return {
299
+ rootDir,
300
+ removedFiles: totalRemovedFiles,
301
+ removedBytes: totalRemovedBytes,
302
+ results,
303
+ };
304
+ }
305
+ /**
306
+ * Cleanup attachments for a single project.
307
+ */
308
+ async cleanupProject(projectId) {
309
+ const dirPath = this.getProjectAttachmentsDir(projectId);
310
+ try {
311
+ // Get stats before deletion
312
+ const stats = await this.getProjectStats(projectId, dirPath);
313
+ if (!stats.exists) {
314
+ return {
315
+ projectId,
316
+ dirPath,
317
+ existed: false,
318
+ removedFiles: 0,
319
+ removedBytes: 0,
320
+ };
321
+ }
322
+ // Remove directory and all contents
323
+ await promises_1.default.rm(dirPath, { recursive: true, force: true });
324
+ console.error(`[AttachmentService] Cleaned up ${stats.fileCount} files (${stats.totalBytes} bytes) for project ${projectId}`);
325
+ return {
326
+ projectId,
327
+ dirPath,
328
+ existed: true,
329
+ removedFiles: stats.fileCount,
330
+ removedBytes: stats.totalBytes,
331
+ };
332
+ }
333
+ catch (error) {
334
+ console.error(`[AttachmentService] Failed to cleanup project ${projectId}:`, error);
335
+ return {
336
+ projectId,
337
+ dirPath,
338
+ existed: false,
339
+ removedFiles: 0,
340
+ removedBytes: 0,
341
+ };
342
+ }
343
+ }
344
+ /**
345
+ * Check if an attachment file exists.
346
+ */
347
+ async attachmentExists(projectId, filename) {
348
+ try {
349
+ const filePath = this.getAttachmentPath(projectId, filename);
350
+ await promises_1.default.access(filePath);
351
+ return true;
352
+ }
353
+ catch (_a) {
354
+ return false;
355
+ }
356
+ }
357
+ /**
358
+ * Read an attachment file.
359
+ */
360
+ async readAttachment(projectId, filename) {
361
+ const filePath = this.getAttachmentPath(projectId, filename);
362
+ return promises_1.default.readFile(filePath);
363
+ }
364
+ }
365
+ exports.AttachmentService = AttachmentService;
366
+ // ============================================================
367
+ // Singleton Export
368
+ // ============================================================
369
+ exports.attachmentService = new AttachmentService();
370
+ //# sourceMappingURL=attachment-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachment-service.js","sourceRoot":"","sources":["../../src/agent/attachment-service.ts"],"names":[],"mappings":"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"}