@yu_robotics/remote-cli 1.0.5 → 1.0.8
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/dist/client/MessageHandler.d.ts +5 -0
- package/dist/client/MessageHandler.d.ts.map +1 -1
- package/dist/client/MessageHandler.js +26 -2
- package/dist/client/MessageHandler.js.map +1 -1
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +13 -0
- package/dist/commands/start.js.map +1 -1
- package/dist/executor/ClaudeExecutor.js +1 -1
- package/dist/executor/ClaudeExecutor.js.map +1 -1
- package/dist/executor/ClaudePersistentExecutor.d.ts +12 -0
- package/dist/executor/ClaudePersistentExecutor.d.ts.map +1 -1
- package/dist/executor/ClaudePersistentExecutor.js +119 -8
- package/dist/executor/ClaudePersistentExecutor.js.map +1 -1
- package/dist/security/HooksConfigurator.d.ts +32 -0
- package/dist/security/HooksConfigurator.d.ts.map +1 -0
- package/dist/security/HooksConfigurator.js +175 -0
- package/dist/security/HooksConfigurator.js.map +1 -0
- package/dist/security/index.d.ts +8 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +14 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/security-guard.d.ts +46 -0
- package/dist/security/security-guard.d.ts.map +1 -0
- package/dist/security/security-guard.js +323 -0
- package/dist/security/security-guard.js.map +1 -0
- package/dist/types/index.d.ts +14 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/FileReadDetector.d.ts +59 -0
- package/dist/utils/FileReadDetector.d.ts.map +1 -0
- package/dist/utils/FileReadDetector.js +116 -0
- package/dist/utils/FileReadDetector.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Security Guard for Claude Code PreToolUse Hooks
|
|
4
|
+
*
|
|
5
|
+
* This module validates tool usage against allowed directory restrictions.
|
|
6
|
+
* It can be used as:
|
|
7
|
+
* 1. A library function (validateToolUse) for testing and programmatic use
|
|
8
|
+
* 2. A standalone script called by Claude Code hooks
|
|
9
|
+
*
|
|
10
|
+
* Exit codes (when run as script):
|
|
11
|
+
* 0 = Allow execution
|
|
12
|
+
* 2 = Block execution (permission denied)
|
|
13
|
+
*/
|
|
14
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
17
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
18
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
19
|
+
}
|
|
20
|
+
Object.defineProperty(o, k2, desc);
|
|
21
|
+
}) : (function(o, m, k, k2) {
|
|
22
|
+
if (k2 === undefined) k2 = k;
|
|
23
|
+
o[k2] = m[k];
|
|
24
|
+
}));
|
|
25
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
26
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
27
|
+
}) : function(o, v) {
|
|
28
|
+
o["default"] = v;
|
|
29
|
+
});
|
|
30
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
31
|
+
var ownKeys = function(o) {
|
|
32
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
33
|
+
var ar = [];
|
|
34
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
35
|
+
return ar;
|
|
36
|
+
};
|
|
37
|
+
return ownKeys(o);
|
|
38
|
+
};
|
|
39
|
+
return function (mod) {
|
|
40
|
+
if (mod && mod.__esModule) return mod;
|
|
41
|
+
var result = {};
|
|
42
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
43
|
+
__setModuleDefault(result, mod);
|
|
44
|
+
return result;
|
|
45
|
+
};
|
|
46
|
+
})();
|
|
47
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
exports.validateToolUse = validateToolUse;
|
|
49
|
+
exports.loadAllowedDirs = loadAllowedDirs;
|
|
50
|
+
exports.main = main;
|
|
51
|
+
const path = __importStar(require("path"));
|
|
52
|
+
const fs = __importStar(require("fs"));
|
|
53
|
+
/**
|
|
54
|
+
* File operation tools that need path validation
|
|
55
|
+
*/
|
|
56
|
+
const FILE_TOOLS = ['Read', 'Write', 'Edit', 'Glob', 'Grep', 'NotebookEdit'];
|
|
57
|
+
/**
|
|
58
|
+
* Dangerous commands that should always be blocked
|
|
59
|
+
*/
|
|
60
|
+
const DANGEROUS_COMMANDS = ['sudo'];
|
|
61
|
+
/**
|
|
62
|
+
* Patterns that indicate piping to a shell (dangerous)
|
|
63
|
+
*/
|
|
64
|
+
const PIPE_TO_SHELL_PATTERNS = [
|
|
65
|
+
/\|\s*bash\b/,
|
|
66
|
+
/\|\s*sh\b/,
|
|
67
|
+
/\|\s*zsh\b/,
|
|
68
|
+
/\|\s*source\b/,
|
|
69
|
+
/\$\(/, // Command substitution
|
|
70
|
+
];
|
|
71
|
+
/**
|
|
72
|
+
* Resolve a path that may contain ~ to an absolute path
|
|
73
|
+
*/
|
|
74
|
+
function resolvePath(filePath, cwd) {
|
|
75
|
+
// Handle tilde expansion
|
|
76
|
+
if (filePath.startsWith('~')) {
|
|
77
|
+
const home = process.env.HOME || '';
|
|
78
|
+
filePath = path.join(home, filePath.slice(1));
|
|
79
|
+
}
|
|
80
|
+
// Handle relative paths
|
|
81
|
+
if (!path.isAbsolute(filePath)) {
|
|
82
|
+
const basePath = cwd || process.cwd();
|
|
83
|
+
filePath = path.resolve(basePath, filePath);
|
|
84
|
+
}
|
|
85
|
+
// Normalize to resolve .. and .
|
|
86
|
+
return path.normalize(filePath);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Resolve an allowed directory path (may contain ~)
|
|
90
|
+
*/
|
|
91
|
+
function resolveAllowedDir(dirPath) {
|
|
92
|
+
if (dirPath.startsWith('~')) {
|
|
93
|
+
const home = process.env.HOME || '';
|
|
94
|
+
return path.normalize(path.join(home, dirPath.slice(1)));
|
|
95
|
+
}
|
|
96
|
+
return path.normalize(path.resolve(dirPath));
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Check if a file path is within any of the allowed directories
|
|
100
|
+
*/
|
|
101
|
+
function isPathWithinAllowed(filePath, allowedDirs) {
|
|
102
|
+
const normalizedFilePath = path.normalize(filePath);
|
|
103
|
+
for (const allowedDir of allowedDirs) {
|
|
104
|
+
const normalizedAllowedDir = resolveAllowedDir(allowedDir);
|
|
105
|
+
// Check if file path starts with allowed directory
|
|
106
|
+
// Must either be exact match or have path separator after allowed dir
|
|
107
|
+
if (normalizedFilePath === normalizedAllowedDir) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
// Ensure we check with trailing separator to prevent prefix attacks
|
|
111
|
+
// e.g., /home/user/app should not match /home/user/app-malicious
|
|
112
|
+
const allowedWithSep = normalizedAllowedDir.endsWith(path.sep)
|
|
113
|
+
? normalizedAllowedDir
|
|
114
|
+
: normalizedAllowedDir + path.sep;
|
|
115
|
+
if (normalizedFilePath.startsWith(allowedWithSep)) {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Extract file path from tool input based on tool type
|
|
123
|
+
*/
|
|
124
|
+
function extractFilePath(toolName, toolInput) {
|
|
125
|
+
// Different tools use different parameter names for file paths
|
|
126
|
+
if (toolName === 'NotebookEdit') {
|
|
127
|
+
return toolInput.notebook_path || null;
|
|
128
|
+
}
|
|
129
|
+
if (toolName === 'Glob' || toolName === 'Grep') {
|
|
130
|
+
// Glob and Grep use 'path' parameter
|
|
131
|
+
return toolInput.path || toolInput.file_path || null;
|
|
132
|
+
}
|
|
133
|
+
// Read, Write, Edit use 'file_path'
|
|
134
|
+
return toolInput.file_path || null;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Extract paths from a bash command
|
|
138
|
+
* Returns an array of paths found in the command
|
|
139
|
+
*/
|
|
140
|
+
function extractPathsFromCommand(command, cwd) {
|
|
141
|
+
const paths = [];
|
|
142
|
+
// Regex patterns to match paths
|
|
143
|
+
// Match absolute paths, tilde paths, and relative paths with common extensions
|
|
144
|
+
const pathPatterns = [
|
|
145
|
+
// Absolute paths starting with /
|
|
146
|
+
/(?:^|\s|=|"'`)(\/[^\s;|&><"'`]+)/g,
|
|
147
|
+
// Tilde paths
|
|
148
|
+
/(?:^|\s|=|"'`)(~\/[^\s;|&><"'`]*)/g,
|
|
149
|
+
// Relative paths starting with ./ or ../
|
|
150
|
+
/(?:^|\s|=|"'`)(\.\.[^\s;|&><"'`]*)/g,
|
|
151
|
+
/(?:^|\s|=|"'`)(\.[^\s;|&><"'`]+)/g,
|
|
152
|
+
];
|
|
153
|
+
for (const pattern of pathPatterns) {
|
|
154
|
+
let match;
|
|
155
|
+
while ((match = pattern.exec(command)) !== null) {
|
|
156
|
+
const potentialPath = match[1].trim();
|
|
157
|
+
// Filter out common non-path strings
|
|
158
|
+
if (potentialPath && !potentialPath.match(/^\.(js|ts|json|md|sh)$/)) {
|
|
159
|
+
paths.push(potentialPath);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return paths;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Validate a Bash command against security restrictions
|
|
167
|
+
*/
|
|
168
|
+
function validateBashCommand(command, cwd, allowedDirs) {
|
|
169
|
+
// Check for dangerous commands
|
|
170
|
+
for (const dangerous of DANGEROUS_COMMANDS) {
|
|
171
|
+
if (new RegExp(`\\b${dangerous}\\b`).test(command)) {
|
|
172
|
+
return {
|
|
173
|
+
allowed: false,
|
|
174
|
+
reason: `Command contains blocked keyword: ${dangerous}`
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// Check for pipe to shell patterns
|
|
179
|
+
for (const pattern of PIPE_TO_SHELL_PATTERNS) {
|
|
180
|
+
if (pattern.test(command)) {
|
|
181
|
+
return {
|
|
182
|
+
allowed: false,
|
|
183
|
+
reason: 'Command contains dangerous pattern: pipe to shell'
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// Extract and validate all paths in the command
|
|
188
|
+
const extractedPaths = extractPathsFromCommand(command, cwd);
|
|
189
|
+
for (const extractedPath of extractedPaths) {
|
|
190
|
+
const resolvedPath = resolvePath(extractedPath, cwd);
|
|
191
|
+
if (!isPathWithinAllowed(resolvedPath, allowedDirs)) {
|
|
192
|
+
return {
|
|
193
|
+
allowed: false,
|
|
194
|
+
reason: `Path "${extractedPath}" is outside allowed directories: ${allowedDirs.join(', ')}`
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
allowed: true,
|
|
200
|
+
reason: 'Command validated successfully'
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Validate tool use against allowed directories
|
|
205
|
+
*
|
|
206
|
+
* @param hookData - Data from Claude Code hook (tool_name, tool_input, etc.)
|
|
207
|
+
* @param allowedDirs - List of allowed directory paths
|
|
208
|
+
* @returns ValidationResult indicating if the operation is allowed
|
|
209
|
+
*/
|
|
210
|
+
function validateToolUse(hookData, allowedDirs) {
|
|
211
|
+
const { tool_name, tool_input, cwd } = hookData;
|
|
212
|
+
// If no restrictions configured, allow everything
|
|
213
|
+
if (!allowedDirs || allowedDirs.length === 0) {
|
|
214
|
+
return {
|
|
215
|
+
allowed: true,
|
|
216
|
+
reason: 'No directory restrictions configured'
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
// Handle Bash tool specially
|
|
220
|
+
if (tool_name === 'Bash') {
|
|
221
|
+
if (!tool_input?.command) {
|
|
222
|
+
return {
|
|
223
|
+
allowed: true,
|
|
224
|
+
reason: 'No command in Bash tool input'
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
return validateBashCommand(tool_input.command, cwd, allowedDirs);
|
|
228
|
+
}
|
|
229
|
+
// Non-file tools (other than Bash) are allowed by default
|
|
230
|
+
if (!FILE_TOOLS.includes(tool_name)) {
|
|
231
|
+
return {
|
|
232
|
+
allowed: true,
|
|
233
|
+
reason: 'Non-file tool'
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
// Handle missing or undefined tool_input
|
|
237
|
+
if (!tool_input) {
|
|
238
|
+
return {
|
|
239
|
+
allowed: true,
|
|
240
|
+
reason: 'No file path in tool input (undefined input)'
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
// Extract file path from tool input
|
|
244
|
+
const filePath = extractFilePath(tool_name, tool_input);
|
|
245
|
+
if (!filePath) {
|
|
246
|
+
return {
|
|
247
|
+
allowed: true,
|
|
248
|
+
reason: 'No file path in tool input'
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
// Resolve the file path to absolute
|
|
252
|
+
const absolutePath = resolvePath(filePath, cwd);
|
|
253
|
+
// Check if path is within allowed directories
|
|
254
|
+
if (isPathWithinAllowed(absolutePath, allowedDirs)) {
|
|
255
|
+
return {
|
|
256
|
+
allowed: true,
|
|
257
|
+
reason: `Path within allowed directory`
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
return {
|
|
261
|
+
allowed: false,
|
|
262
|
+
reason: `Path "${filePath}" is outside allowed directories: ${allowedDirs.join(', ')}`
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Load allowed directories from config file
|
|
267
|
+
* If lastWorkingDirectory is set, use it as the primary allowed directory
|
|
268
|
+
*/
|
|
269
|
+
function loadAllowedDirs(configPath) {
|
|
270
|
+
const effectivePath = configPath ||
|
|
271
|
+
process.env.REMOTE_CLI_CONFIG ||
|
|
272
|
+
path.join(process.env.HOME || '', '.remote-cli', 'config.json');
|
|
273
|
+
try {
|
|
274
|
+
const config = JSON.parse(fs.readFileSync(effectivePath, 'utf8'));
|
|
275
|
+
// If lastWorkingDirectory is set, use it as the primary (and only) allowed directory
|
|
276
|
+
// This ensures security is tied to the current working directory
|
|
277
|
+
if (config.lastWorkingDirectory) {
|
|
278
|
+
return [config.lastWorkingDirectory];
|
|
279
|
+
}
|
|
280
|
+
// Fallback to allowedDirectories if no working directory is set
|
|
281
|
+
return config.security?.allowedDirectories || [];
|
|
282
|
+
}
|
|
283
|
+
catch {
|
|
284
|
+
return [];
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Main function when run as a script
|
|
289
|
+
* Reads hook data from stdin and exits with appropriate code
|
|
290
|
+
*/
|
|
291
|
+
async function main() {
|
|
292
|
+
let input = '';
|
|
293
|
+
// Read from stdin
|
|
294
|
+
process.stdin.setEncoding('utf8');
|
|
295
|
+
for await (const chunk of process.stdin) {
|
|
296
|
+
input += chunk;
|
|
297
|
+
}
|
|
298
|
+
try {
|
|
299
|
+
const hookData = JSON.parse(input);
|
|
300
|
+
const allowedDirs = loadAllowedDirs();
|
|
301
|
+
// If no allowed directories are configured, allow everything (fallback)
|
|
302
|
+
if (allowedDirs.length === 0) {
|
|
303
|
+
console.error('[SecurityGuard] Warning: No working directory configured, allowing all operations');
|
|
304
|
+
process.exit(0);
|
|
305
|
+
}
|
|
306
|
+
const result = validateToolUse(hookData, allowedDirs);
|
|
307
|
+
if (!result.allowed) {
|
|
308
|
+
console.error(`[SecurityGuard] Blocked: ${result.reason}`);
|
|
309
|
+
process.exit(2);
|
|
310
|
+
}
|
|
311
|
+
process.exit(0);
|
|
312
|
+
}
|
|
313
|
+
catch (error) {
|
|
314
|
+
console.error(`[SecurityGuard] Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
315
|
+
// Allow on error to avoid blocking legitimate operations
|
|
316
|
+
process.exit(0);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
// Run main if executed directly
|
|
320
|
+
if (require.main === module) {
|
|
321
|
+
main();
|
|
322
|
+
}
|
|
323
|
+
//# sourceMappingURL=security-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security-guard.js","sourceRoot":"","sources":["../../src/security/security-guard.ts"],"names":[],"mappings":"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"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export interface ToolResultInfo {
|
|
|
17
17
|
/**
|
|
18
18
|
* Content block types for structured streaming messages
|
|
19
19
|
*/
|
|
20
|
-
export type ContentBlockType = 'text' | 'tool_use' | 'tool_result' | 'divider';
|
|
20
|
+
export type ContentBlockType = 'text' | 'tool_use' | 'tool_result' | 'divider' | 'redacted_thinking';
|
|
21
21
|
/**
|
|
22
22
|
* Base content block interface
|
|
23
23
|
*/
|
|
@@ -51,10 +51,21 @@ export interface ToolResultBlock extends ContentBlock {
|
|
|
51
51
|
export interface DividerBlock extends ContentBlock {
|
|
52
52
|
type: 'divider';
|
|
53
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Redacted thinking content block (for safety-filtered reasoning)
|
|
56
|
+
* When Claude's or other AI models' internal reasoning is flagged by safety systems,
|
|
57
|
+
* the thinking block is encrypted and returned as redacted_thinking.
|
|
58
|
+
* This applies to Claude 3.7 Sonnet and Gemini models.
|
|
59
|
+
*/
|
|
60
|
+
export interface RedactedThinkingBlock extends ContentBlock {
|
|
61
|
+
type: 'redacted_thinking';
|
|
62
|
+
/** Encrypted thinking content (not human-readable) */
|
|
63
|
+
redacted_thinking: string;
|
|
64
|
+
}
|
|
54
65
|
/**
|
|
55
66
|
* Union type for all content blocks
|
|
56
67
|
*/
|
|
57
|
-
export type ContentBlockUnion = TextBlock | ToolUseBlock | ToolResultBlock | DividerBlock;
|
|
68
|
+
export type ContentBlockUnion = TextBlock | ToolUseBlock | ToolResultBlock | DividerBlock | RedactedThinkingBlock;
|
|
58
69
|
/**
|
|
59
70
|
* Structured content for rich message formatting
|
|
60
71
|
*/
|
|
@@ -80,7 +91,7 @@ export interface IncomingMessage {
|
|
|
80
91
|
/**
|
|
81
92
|
* Stream message types
|
|
82
93
|
*/
|
|
83
|
-
export type StreamType = 'text' | 'tool_use' | 'tool_result';
|
|
94
|
+
export type StreamType = 'text' | 'tool_use' | 'tool_result' | 'redacted_thinking';
|
|
84
95
|
/**
|
|
85
96
|
* Outgoing message to router server
|
|
86
97
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,UAAU,GAAG,aAAa,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Read Intent Detection
|
|
3
|
+
*
|
|
4
|
+
* Detects when a user message indicates intent to read/view a file,
|
|
5
|
+
* and injects a system hint telling Claude Code to show only the
|
|
6
|
+
* first 50 lines by default. This optimizes mobile (Feishu) experience
|
|
7
|
+
* by reducing token usage and response length.
|
|
8
|
+
*
|
|
9
|
+
* Users can bypass with `--full` or `全部显示` markers.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* processFileReadContent('读取 config.ts')
|
|
13
|
+
* // Returns: '读取 config.ts\n\n[System hint: ...]'
|
|
14
|
+
*
|
|
15
|
+
* processFileReadContent('读取 config.ts --full')
|
|
16
|
+
* // Returns: '读取 config.ts' (no hint, marker stripped)
|
|
17
|
+
*
|
|
18
|
+
* processFileReadContent('fix the bug')
|
|
19
|
+
* // Returns: 'fix the bug' (unchanged)
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Check if content contains skip markers (--full or 全部显示)
|
|
23
|
+
*
|
|
24
|
+
* @param content User message content
|
|
25
|
+
* @returns true if content contains skip markers
|
|
26
|
+
*/
|
|
27
|
+
export declare function shouldSkipHint(content: string): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Detect if user message indicates intent to read/view a file
|
|
30
|
+
*
|
|
31
|
+
* Matches three categories:
|
|
32
|
+
* 1. Chinese keywords (读取, 查看, 看看, etc.)
|
|
33
|
+
* 2. English phrases (read file, show me, cat, etc.)
|
|
34
|
+
* 3. File path + action verb combo (show src/index.ts, 看 config.yaml)
|
|
35
|
+
*
|
|
36
|
+
* @param content User message content
|
|
37
|
+
* @returns true if file-reading intent is detected
|
|
38
|
+
*/
|
|
39
|
+
export declare function hasFileReadIntent(content: string): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Append system hint to content for file-reading requests
|
|
42
|
+
*
|
|
43
|
+
* @param content User message content
|
|
44
|
+
* @returns Content with system hint appended
|
|
45
|
+
*/
|
|
46
|
+
export declare function injectFileReadHint(content: string): string;
|
|
47
|
+
/**
|
|
48
|
+
* Process content for file-reading intent detection
|
|
49
|
+
*
|
|
50
|
+
* Orchestrates the full flow:
|
|
51
|
+
* 1. If skip markers present → strip them, return cleaned content (no hint)
|
|
52
|
+
* 2. If file-reading intent detected → inject hint
|
|
53
|
+
* 3. Otherwise → return content unchanged
|
|
54
|
+
*
|
|
55
|
+
* @param content User message content
|
|
56
|
+
* @returns Processed content (with hint injected, markers stripped, or unchanged)
|
|
57
|
+
*/
|
|
58
|
+
export declare function processFileReadContent(content: string): string;
|
|
59
|
+
//# sourceMappingURL=FileReadDetector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileReadDetector.d.ts","sourceRoot":"","sources":["../../src/utils/FileReadDetector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAqBH;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAKvD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAkB1D;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAK1D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAc9D"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* File Read Intent Detection
|
|
4
|
+
*
|
|
5
|
+
* Detects when a user message indicates intent to read/view a file,
|
|
6
|
+
* and injects a system hint telling Claude Code to show only the
|
|
7
|
+
* first 50 lines by default. This optimizes mobile (Feishu) experience
|
|
8
|
+
* by reducing token usage and response length.
|
|
9
|
+
*
|
|
10
|
+
* Users can bypass with `--full` or `全部显示` markers.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* processFileReadContent('读取 config.ts')
|
|
14
|
+
* // Returns: '读取 config.ts\n\n[System hint: ...]'
|
|
15
|
+
*
|
|
16
|
+
* processFileReadContent('读取 config.ts --full')
|
|
17
|
+
* // Returns: '读取 config.ts' (no hint, marker stripped)
|
|
18
|
+
*
|
|
19
|
+
* processFileReadContent('fix the bug')
|
|
20
|
+
* // Returns: 'fix the bug' (unchanged)
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.shouldSkipHint = shouldSkipHint;
|
|
24
|
+
exports.hasFileReadIntent = hasFileReadIntent;
|
|
25
|
+
exports.injectFileReadHint = injectFileReadHint;
|
|
26
|
+
exports.processFileReadContent = processFileReadContent;
|
|
27
|
+
const CHINESE_KEYWORDS = /读取|查看|看看|展示|显示|打开文件|文件内容|看下|看一下/;
|
|
28
|
+
const ENGLISH_PHRASES = /\b(?:read|show|view|display|open|print)\s+(?:the\s+)?file\b|\bshow\s+me\b|\bcat\s+\S/i;
|
|
29
|
+
const FILE_EXTENSION = /\S+\.\w{1,5}\b/;
|
|
30
|
+
const ACTION_VERB = /读|看|查|show|read|cat|view|display|open|print/i;
|
|
31
|
+
const SKIP_MARKER = /--full/i;
|
|
32
|
+
const SKIP_MARKER_CN = /全部显示/;
|
|
33
|
+
const SYSTEM_HINT = '[System hint: For files exceeding 50 lines, show only the first 50 lines by default with a summary of remaining content. Ask the user if they want to see more.]';
|
|
34
|
+
/**
|
|
35
|
+
* Remove skip markers (--full, 全部显示) from content
|
|
36
|
+
*/
|
|
37
|
+
function stripSkipMarkers(content) {
|
|
38
|
+
return content
|
|
39
|
+
.replace(SKIP_MARKER, '')
|
|
40
|
+
.replace(SKIP_MARKER_CN, '')
|
|
41
|
+
.trim();
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Check if content contains skip markers (--full or 全部显示)
|
|
45
|
+
*
|
|
46
|
+
* @param content User message content
|
|
47
|
+
* @returns true if content contains skip markers
|
|
48
|
+
*/
|
|
49
|
+
function shouldSkipHint(content) {
|
|
50
|
+
if (!content) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
return SKIP_MARKER.test(content) || SKIP_MARKER_CN.test(content);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Detect if user message indicates intent to read/view a file
|
|
57
|
+
*
|
|
58
|
+
* Matches three categories:
|
|
59
|
+
* 1. Chinese keywords (读取, 查看, 看看, etc.)
|
|
60
|
+
* 2. English phrases (read file, show me, cat, etc.)
|
|
61
|
+
* 3. File path + action verb combo (show src/index.ts, 看 config.yaml)
|
|
62
|
+
*
|
|
63
|
+
* @param content User message content
|
|
64
|
+
* @returns true if file-reading intent is detected
|
|
65
|
+
*/
|
|
66
|
+
function hasFileReadIntent(content) {
|
|
67
|
+
if (!content) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
if (CHINESE_KEYWORDS.test(content)) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
if (ENGLISH_PHRASES.test(content)) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
if (FILE_EXTENSION.test(content) && ACTION_VERB.test(content)) {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Append system hint to content for file-reading requests
|
|
83
|
+
*
|
|
84
|
+
* @param content User message content
|
|
85
|
+
* @returns Content with system hint appended
|
|
86
|
+
*/
|
|
87
|
+
function injectFileReadHint(content) {
|
|
88
|
+
if (!content) {
|
|
89
|
+
return '';
|
|
90
|
+
}
|
|
91
|
+
return `${content}\n\n${SYSTEM_HINT}`;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Process content for file-reading intent detection
|
|
95
|
+
*
|
|
96
|
+
* Orchestrates the full flow:
|
|
97
|
+
* 1. If skip markers present → strip them, return cleaned content (no hint)
|
|
98
|
+
* 2. If file-reading intent detected → inject hint
|
|
99
|
+
* 3. Otherwise → return content unchanged
|
|
100
|
+
*
|
|
101
|
+
* @param content User message content
|
|
102
|
+
* @returns Processed content (with hint injected, markers stripped, or unchanged)
|
|
103
|
+
*/
|
|
104
|
+
function processFileReadContent(content) {
|
|
105
|
+
if (!content) {
|
|
106
|
+
return content;
|
|
107
|
+
}
|
|
108
|
+
if (shouldSkipHint(content)) {
|
|
109
|
+
return stripSkipMarkers(content);
|
|
110
|
+
}
|
|
111
|
+
if (hasFileReadIntent(content)) {
|
|
112
|
+
return injectFileReadHint(content);
|
|
113
|
+
}
|
|
114
|
+
return content;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=FileReadDetector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileReadDetector.js","sourceRoot":"","sources":["../../src/utils/FileReadDetector.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;AA2BH,wCAKC;AAaD,8CAkBC;AAQD,gDAKC;AAaD,wDAcC;AArGD,MAAM,gBAAgB,GAAG,iCAAiC,CAAA;AAC1D,MAAM,eAAe,GAAG,uFAAuF,CAAA;AAC/G,MAAM,cAAc,GAAG,gBAAgB,CAAA;AACvC,MAAM,WAAW,GAAG,8CAA8C,CAAA;AAClE,MAAM,WAAW,GAAG,SAAS,CAAA;AAC7B,MAAM,cAAc,GAAG,MAAM,CAAA;AAE7B,MAAM,WAAW,GAAG,kKAAkK,CAAA;AAEtL;;GAEG;AACH,SAAS,gBAAgB,CAAC,OAAe;IACvC,OAAO,OAAO;SACX,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;SACxB,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC;SAC3B,IAAI,EAAE,CAAA;AACX,CAAC;AAED;;;;;GAKG;AACH,SAAgB,cAAc,CAAC,OAAe;IAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,KAAK,CAAA;IACd,CAAC;IACD,OAAO,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;AAClE,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAgB,iBAAiB,CAAC,OAAe;IAC/C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,KAAK,CAAA;IACd,CAAC;IAED,IAAI,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACnC,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IAAI,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAClC,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IAAI,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9D,OAAO,IAAI,CAAA;IACb,CAAC;IAED,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;;GAKG;AACH,SAAgB,kBAAkB,CAAC,OAAe;IAChD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,CAAA;IACX,CAAC;IACD,OAAO,GAAG,OAAO,OAAO,WAAW,EAAE,CAAA;AACvC,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAgB,sBAAsB,CAAC,OAAe;IACpD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,OAAO,CAAA;IAChB,CAAC;IAED,IAAI,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,OAAO,gBAAgB,CAAC,OAAO,CAAC,CAAA;IAClC,CAAC;IAED,IAAI,iBAAiB,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/B,OAAO,kBAAkB,CAAC,OAAO,CAAC,CAAA;IACpC,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC"}
|