@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.
Files changed (32) hide show
  1. package/dist/client/MessageHandler.d.ts +5 -0
  2. package/dist/client/MessageHandler.d.ts.map +1 -1
  3. package/dist/client/MessageHandler.js +26 -2
  4. package/dist/client/MessageHandler.js.map +1 -1
  5. package/dist/commands/start.d.ts.map +1 -1
  6. package/dist/commands/start.js +13 -0
  7. package/dist/commands/start.js.map +1 -1
  8. package/dist/executor/ClaudeExecutor.js +1 -1
  9. package/dist/executor/ClaudeExecutor.js.map +1 -1
  10. package/dist/executor/ClaudePersistentExecutor.d.ts +12 -0
  11. package/dist/executor/ClaudePersistentExecutor.d.ts.map +1 -1
  12. package/dist/executor/ClaudePersistentExecutor.js +119 -8
  13. package/dist/executor/ClaudePersistentExecutor.js.map +1 -1
  14. package/dist/security/HooksConfigurator.d.ts +32 -0
  15. package/dist/security/HooksConfigurator.d.ts.map +1 -0
  16. package/dist/security/HooksConfigurator.js +175 -0
  17. package/dist/security/HooksConfigurator.js.map +1 -0
  18. package/dist/security/index.d.ts +8 -0
  19. package/dist/security/index.d.ts.map +1 -0
  20. package/dist/security/index.js +14 -0
  21. package/dist/security/index.js.map +1 -0
  22. package/dist/security/security-guard.d.ts +46 -0
  23. package/dist/security/security-guard.d.ts.map +1 -0
  24. package/dist/security/security-guard.js +323 -0
  25. package/dist/security/security-guard.js.map +1 -0
  26. package/dist/types/index.d.ts +14 -3
  27. package/dist/types/index.d.ts.map +1 -1
  28. package/dist/utils/FileReadDetector.d.ts +59 -0
  29. package/dist/utils/FileReadDetector.d.ts.map +1 -0
  30. package/dist/utils/FileReadDetector.js +116 -0
  31. package/dist/utils/FileReadDetector.js.map +1 -0
  32. 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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"}
@@ -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;AAE/E;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,gBAAgB,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,SAAU,SAAQ,YAAY;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,YAAa,SAAQ,YAAY;IAChD,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,WAAW,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACnD,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,cAAc,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,YAAa,SAAQ,YAAY;IAChD,IAAI,EAAE,SAAS,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,YAAY,GAAG,eAAe,GAAG,YAAY,CAAC;AAE1F;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,8BAA8B;IAC9B,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,aAAa,CAAC;AAE7D;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,YAAY,GAAG,QAAQ,CAAC;IAC1E,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,qDAAqD;IACrD,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,2DAA2D;IAC3D,UAAU,CAAC,EAAE,cAAc,CAAC;CAC7B"}
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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yu_robotics/remote-cli",
3
- "version": "1.0.5",
3
+ "version": "1.0.8",
4
4
  "description": "Remote control Claude Code CLI via mobile",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",