mattermost-claude-code 0.7.0 → 0.7.2
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/claude/session.d.ts
CHANGED
package/dist/claude/session.js
CHANGED
|
@@ -131,6 +131,7 @@ export class SessionManager {
|
|
|
131
131
|
updateTimer: null,
|
|
132
132
|
typingTimer: null,
|
|
133
133
|
timeoutWarningPosted: false,
|
|
134
|
+
isRestarting: false,
|
|
134
135
|
};
|
|
135
136
|
// Register session
|
|
136
137
|
this.sessions.set(actualThreadId, session);
|
|
@@ -220,14 +221,11 @@ export class SessionManager {
|
|
|
220
221
|
}
|
|
221
222
|
}
|
|
222
223
|
async handleExitPlanMode(session) {
|
|
223
|
-
// If already approved in this session,
|
|
224
|
+
// If already approved in this session, silently ignore subsequent ExitPlanMode calls
|
|
225
|
+
// (Don't send another message - that causes Claude to loop)
|
|
224
226
|
if (session.planApproved) {
|
|
225
227
|
if (this.debug)
|
|
226
|
-
console.log(' ↪ Plan already approved,
|
|
227
|
-
if (session.claude.isRunning()) {
|
|
228
|
-
session.claude.sendMessage('Continue with the implementation.');
|
|
229
|
-
this.startTyping(session);
|
|
230
|
-
}
|
|
228
|
+
console.log(' ↪ Plan already approved, ignoring ExitPlanMode');
|
|
231
229
|
return;
|
|
232
230
|
}
|
|
233
231
|
// If we already have a pending approval, don't post another one
|
|
@@ -713,6 +711,10 @@ export class SessionManager {
|
|
|
713
711
|
const session = this.sessions.get(threadId);
|
|
714
712
|
if (!session)
|
|
715
713
|
return;
|
|
714
|
+
// If we're intentionally restarting (e.g., !cd), don't clean up or post exit message
|
|
715
|
+
if (session.isRestarting) {
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
716
718
|
this.stopTyping(session);
|
|
717
719
|
if (session.updateTimer) {
|
|
718
720
|
clearTimeout(session.updateTimer);
|
|
@@ -813,6 +815,7 @@ export class SessionManager {
|
|
|
813
815
|
console.log(` 📂 Session (${shortId}…) changing directory to ${shortDir}`);
|
|
814
816
|
// Stop the current Claude CLI
|
|
815
817
|
this.stopTyping(session);
|
|
818
|
+
session.isRestarting = true; // Suppress exit message during restart
|
|
816
819
|
session.claude.kill();
|
|
817
820
|
// Flush any pending content
|
|
818
821
|
await this.flush(session);
|
|
@@ -833,8 +836,10 @@ export class SessionManager {
|
|
|
833
836
|
// Start the new Claude CLI
|
|
834
837
|
try {
|
|
835
838
|
session.claude.start();
|
|
839
|
+
session.isRestarting = false; // Successfully restarted
|
|
836
840
|
}
|
|
837
841
|
catch (err) {
|
|
842
|
+
session.isRestarting = false; // Reset flag even on failure
|
|
838
843
|
console.error(' ❌ Failed to restart Claude:', err);
|
|
839
844
|
await this.mattermost.createPost(`❌ Failed to restart Claude: ${err}`, threadId);
|
|
840
845
|
return;
|
|
@@ -29,6 +29,7 @@ export declare class MattermostClient extends EventEmitter {
|
|
|
29
29
|
createPost(message: string, threadId?: string): Promise<MattermostPost>;
|
|
30
30
|
updatePost(postId: string, message: string): Promise<MattermostPost>;
|
|
31
31
|
addReaction(postId: string, emojiName: string): Promise<void>;
|
|
32
|
+
downloadFile(fileId: string): Promise<Buffer>;
|
|
32
33
|
connect(): Promise<void>;
|
|
33
34
|
private handleEvent;
|
|
34
35
|
private scheduleReconnect;
|
|
@@ -88,6 +88,20 @@ export class MattermostClient extends EventEmitter {
|
|
|
88
88
|
emoji_name: emojiName,
|
|
89
89
|
});
|
|
90
90
|
}
|
|
91
|
+
// Download a file attachment
|
|
92
|
+
async downloadFile(fileId) {
|
|
93
|
+
const url = `${this.config.mattermost.url}/api/v4/files/${fileId}`;
|
|
94
|
+
const response = await fetch(url, {
|
|
95
|
+
headers: {
|
|
96
|
+
Authorization: `Bearer ${this.config.mattermost.token}`,
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
if (!response.ok) {
|
|
100
|
+
throw new Error(`Failed to download file ${fileId}: ${response.status}`);
|
|
101
|
+
}
|
|
102
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
103
|
+
return Buffer.from(arrayBuffer);
|
|
104
|
+
}
|
|
91
105
|
// Connect to WebSocket
|
|
92
106
|
async connect() {
|
|
93
107
|
// Get bot user first
|
|
@@ -8,6 +8,15 @@ export interface MattermostWebSocketEvent {
|
|
|
8
8
|
};
|
|
9
9
|
seq: number;
|
|
10
10
|
}
|
|
11
|
+
export interface MattermostFile {
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
size: number;
|
|
15
|
+
mime_type: string;
|
|
16
|
+
extension: string;
|
|
17
|
+
width?: number;
|
|
18
|
+
height?: number;
|
|
19
|
+
}
|
|
11
20
|
export interface MattermostPost {
|
|
12
21
|
id: string;
|
|
13
22
|
create_at: number;
|
|
@@ -21,7 +30,7 @@ export interface MattermostPost {
|
|
|
21
30
|
props: Record<string, unknown>;
|
|
22
31
|
metadata?: {
|
|
23
32
|
embeds?: unknown[];
|
|
24
|
-
files?:
|
|
33
|
+
files?: MattermostFile[];
|
|
25
34
|
};
|
|
26
35
|
}
|
|
27
36
|
export interface MattermostUser {
|