chatccc 0.2.151 → 0.2.153
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/im-skills/feishu-skill/receive-send-file.md +63 -66
- package/im-skills/feishu-skill/receive-send-image.md +24 -27
- package/package.json +1 -1
- package/src/adapters/adapter-interface.ts +4 -0
- package/src/adapters/claude-adapter.ts +2 -0
- package/src/agent-stop-stuck.ts +2 -0
- package/src/session-chat-binding.ts +4 -0
- package/src/session.ts +4 -0
|
@@ -1,67 +1,64 @@
|
|
|
1
|
-
# Sending & Downloading Files/Videos
|
|
2
|
-
|
|
3
|
-
## Send Files or Videos
|
|
4
|
-
|
|
5
|
-
Videos are sent as regular files (not media), which looks cleaner in Feishu.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
|
35
|
-
|
|
36
|
-
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
node "{{download_video_script}}" --chat-id <chat_id> --file-key <file_key> --name <file_name>
|
|
65
|
-
```
|
|
66
|
-
|
|
1
|
+
# Sending & Downloading Files/Videos
|
|
2
|
+
|
|
3
|
+
## Send Files or Videos
|
|
4
|
+
|
|
5
|
+
Videos are sent as regular files (not media), which looks cleaner in Feishu.
|
|
6
|
+
|
|
7
|
+
**Use the node script below. Do NOT use curl or raw HTTP — the script correctly handles errors and exits non-zero on failure.**
|
|
8
|
+
|
|
9
|
+
### Script
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
node "{{send_file_script}}" --url "{{send_file_url}}" --session-id "{{session_id}}" --path "<absolute file path>" --caption "<optional caption>"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Rules
|
|
16
|
+
|
|
17
|
+
- Use the node script above — never curl or raw HTTP.
|
|
18
|
+
- Save or choose a local file first.
|
|
19
|
+
- Use an absolute local path.
|
|
20
|
+
- Max file size: 30MB.
|
|
21
|
+
- Supported formats: .mp4 .mov .avi .mkv .webm .flv .mp3 .wav .ogg .aac .m4a .pdf .doc .docx .xls .xlsx .csv .ppt .pptx .txt .zip .tar .gz.
|
|
22
|
+
- Only send a file/video when the user asked for one or when it materially helps the answer.
|
|
23
|
+
- **If the script fails (non-zero exit), read stderr for the error. Do NOT retry with the same path. Either fix the problem (wrong extension, missing file, etc.) or tell the user what the error was. Never retry more than once.**
|
|
24
|
+
|
|
25
|
+
### Video Compression (when file > 30MB)
|
|
26
|
+
|
|
27
|
+
If the video exceeds 30MB, compress it with ffmpeg before sending.
|
|
28
|
+
|
|
29
|
+
**Ensure ffmpeg is available** (install if missing):
|
|
30
|
+
|
|
31
|
+
| OS | Install command |
|
|
32
|
+
|----|----------------|
|
|
33
|
+
| macOS | `brew install ffmpeg` |
|
|
34
|
+
| Linux (Debian/Ubuntu) | `sudo apt install ffmpeg` |
|
|
35
|
+
| Linux (RHEL/Fedora) | `sudo dnf install ffmpeg` |
|
|
36
|
+
| Windows | `winget install Gyan.FFmpeg` |
|
|
37
|
+
|
|
38
|
+
**Two-pass compression** (target ~28MB for 30s video, adjust `b:v` for other durations):
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
ffmpeg -y -i "<input>" -c:v libx264 -b:v <bitrate>k -pass 1 -f mp4 NUL
|
|
42
|
+
ffmpeg -y -i "<input>" -c:v libx264 -b:v <bitrate>k -pass 2 -c:a aac -b:a 128k "<output>"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Bitrate formula: `bitrate = 28 × 8 × 1000 ÷ duration_seconds - 128` (target ~28MB, safe under 30MB).
|
|
46
|
+
On Windows replace `NUL` with `NUL` (same); on Linux/macOS use `/dev/null`.
|
|
47
|
+
|
|
48
|
+
If the compressed file still exceeds 30MB, explain to the user that automatic compression wasn't enough and suggest they manually trim or re-encode the source.
|
|
49
|
+
|
|
50
|
+
## Download Files or Videos
|
|
51
|
+
|
|
52
|
+
When the user sends a file or video to the bot, the message contains `message_id` and `file_key`. Download it with:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
node "{{download_video_script}}" --message-id <message_id> --file-key <file_key> --name <file_name>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
If only `chat_id` and `file_key` are available:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
node "{{download_video_script}}" --chat-id <chat_id> --file-key <file_key> --name <file_name>
|
|
62
|
+
```
|
|
63
|
+
|
|
67
64
|
Downloads are saved under `~/.chatccc/videos/downloads/`.
|
|
@@ -1,28 +1,25 @@
|
|
|
1
|
-
# Sending & Receiving Images
|
|
2
|
-
|
|
3
|
-
## Send Images
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
## Receive Images
|
|
27
|
-
|
|
1
|
+
# Sending & Receiving Images
|
|
2
|
+
|
|
3
|
+
## Send Images
|
|
4
|
+
|
|
5
|
+
**Use the node script below. Do NOT use curl or raw HTTP — the script correctly handles errors and exits non-zero on failure.**
|
|
6
|
+
|
|
7
|
+
### Script
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
node "{{send_image_script}}" --url "{{send_image_url}}" --session-id "{{session_id}}" --path "<absolute image path>" --caption "<optional caption>"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Rules
|
|
14
|
+
|
|
15
|
+
- Use the node script above — never curl or raw HTTP.
|
|
16
|
+
- Save or choose a local image file first.
|
|
17
|
+
- Use an absolute local path.
|
|
18
|
+
- Supported formats: .png, .jpg, .jpeg, .webp, .gif, .bmp.
|
|
19
|
+
- Max image size: 10MB.
|
|
20
|
+
- Only send an image when the user asked for one or when it materially helps the answer.
|
|
21
|
+
- **If the script fails (non-zero exit), read stderr for the error. Do NOT retry with the same path. Either fix the problem (wrong extension, missing file, etc.) or tell the user what the error was. Never retry more than once.**
|
|
22
|
+
|
|
23
|
+
## Receive Images
|
|
24
|
+
|
|
28
25
|
Images sent to the bot are automatically downloaded to `~/.chatccc/images/downloads/`. The message contains an `image_key` that maps to the cached file.
|
package/package.json
CHANGED
|
@@ -128,6 +128,10 @@ export interface ToolPromptOptions {
|
|
|
128
128
|
onProcessStart?: (info: ToolProcessInfo) => void;
|
|
129
129
|
/** Called when the adapter leaves the prompt process scope normally or by abort. */
|
|
130
130
|
onProcessExit?: (info: ToolProcessInfo) => void;
|
|
131
|
+
/** Called when the adapter creates an SDK session internally.
|
|
132
|
+
* The callback receives a close function that terminates the underlying
|
|
133
|
+
* subprocess. Used by stop-stuck-loop to kill the CLI process immediately. */
|
|
134
|
+
onSessionCreated?: (closeSession: () => void) => void;
|
|
131
135
|
}
|
|
132
136
|
|
|
133
137
|
// ---------------------------------------------------------------------------
|
|
@@ -490,6 +490,8 @@ class ClaudeAdapter implements ToolAdapter {
|
|
|
490
490
|
})),
|
|
491
491
|
);
|
|
492
492
|
|
|
493
|
+
options?.onSessionCreated?.(() => session.close());
|
|
494
|
+
|
|
493
495
|
try {
|
|
494
496
|
await session.send(buildClaudePromptText(userText, undefined, sessionId));
|
|
495
497
|
for await (const raw of session.stream()) {
|
package/src/agent-stop-stuck.ts
CHANGED
|
@@ -73,6 +73,10 @@ export interface ActivePrompt {
|
|
|
73
73
|
abnormalExitNotified?: boolean;
|
|
74
74
|
/** Set when the resource monitor detects CPU + memory unchanged for 3 minutes. */
|
|
75
75
|
resourceStuck?: boolean;
|
|
76
|
+
/** Adapter-provided callback to close the underlying SDK session / subprocess.
|
|
77
|
+
* Called by stop-stuck-loop before controller.abort() to terminate the CLI
|
|
78
|
+
* process immediately, rather than waiting for the async generator to unblock. */
|
|
79
|
+
closeSession?: () => void;
|
|
76
80
|
}
|
|
77
81
|
|
|
78
82
|
export const activePrompts = new Map<string, ActivePrompt>();
|
package/src/session.ts
CHANGED
|
@@ -1110,6 +1110,10 @@ export async function runAgentSession(
|
|
|
1110
1110
|
clearPromptProcessMonitor(sessionId);
|
|
1111
1111
|
if (exitInfo.pid !== undefined) unregisterProcess(exitInfo.pid);
|
|
1112
1112
|
},
|
|
1113
|
+
onSessionCreated: (closeSession) => {
|
|
1114
|
+
const prompt = activePrompts.get(sessionId);
|
|
1115
|
+
if (prompt) prompt.closeSession = closeSession;
|
|
1116
|
+
},
|
|
1113
1117
|
})) {
|
|
1114
1118
|
for (const block of unifiedMsg.blocks) {
|
|
1115
1119
|
accumulateBlockContent(block, state, toolCallMap);
|