instar 0.25.2 → 0.25.4
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/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +205 -58
- package/dist/commands/server.js.map +1 -1
- package/dist/messaging/slack/SlackAdapter.d.ts +37 -2
- package/dist/messaging/slack/SlackAdapter.d.ts.map +1 -1
- package/dist/messaging/slack/SlackAdapter.js +150 -3
- package/dist/messaging/slack/SlackAdapter.js.map +1 -1
- package/dist/monitoring/PresenceProxy.d.ts.map +1 -1
- package/dist/monitoring/PresenceProxy.js +11 -2
- package/dist/monitoring/PresenceProxy.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +7 -0
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/scripts/pre-push-gate.js +28 -0
- package/src/data/builtin-manifest.json +46 -46
- package/upgrades/0.25.3.md +25 -0
- package/upgrades/0.25.4.md +24 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA0PH,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAsnCD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA0PH,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAsnCD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAslHtE;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDzE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuD5E"}
|
package/dist/commands/server.js
CHANGED
|
@@ -2515,10 +2515,15 @@ export async function startServer(options) {
|
|
|
2515
2515
|
clearTimeout(timer);
|
|
2516
2516
|
}
|
|
2517
2517
|
};
|
|
2518
|
-
//
|
|
2518
|
+
// Wire intelligence provider for LLM-gated stall confirmation
|
|
2519
|
+
if (sharedIntelligence) {
|
|
2520
|
+
slackAdapter.intelligence = sharedIntelligence;
|
|
2521
|
+
}
|
|
2522
|
+
// Start stall detection timer (with promise tracking)
|
|
2519
2523
|
const stallTimeout = slackConfig.config.stallTimeoutMinutes ?? 5;
|
|
2524
|
+
const promiseTimeout = slackConfig.config.promiseTimeoutMinutes ?? 10;
|
|
2520
2525
|
if (stallTimeout > 0) {
|
|
2521
|
-
slackAdapter.startStallDetection(stallTimeout * 60 * 1000);
|
|
2526
|
+
slackAdapter.startStallDetection(stallTimeout * 60 * 1000, promiseTimeout * 60 * 1000);
|
|
2522
2527
|
}
|
|
2523
2528
|
// Wire session management callbacks for slash commands
|
|
2524
2529
|
slackAdapter.onInterruptSession = async (sessionName) => {
|
|
@@ -2559,7 +2564,7 @@ export async function startServer(options) {
|
|
|
2559
2564
|
sessionManager.sendKey(sessionName, value);
|
|
2560
2565
|
console.log(`[slack] Prompt response injected: session="${sessionName}" key="${value}"`);
|
|
2561
2566
|
};
|
|
2562
|
-
// Standby commands will be wired after PresenceProxy
|
|
2567
|
+
// Standby commands and triage status will be wired after PresenceProxy/TriageOrchestrator (below)
|
|
2563
2568
|
}
|
|
2564
2569
|
catch (err) {
|
|
2565
2570
|
const reason = err instanceof Error ? err.message : String(err);
|
|
@@ -2856,32 +2861,63 @@ export async function startServer(options) {
|
|
|
2856
2861
|
console.log(pc.green(' Session Watchdog enabled'));
|
|
2857
2862
|
}
|
|
2858
2863
|
// StallTriageNurse — LLM-powered session recovery (uses shared intelligence)
|
|
2864
|
+
// Platform-aware: works with Telegram topics AND Slack channels
|
|
2859
2865
|
let triageNurse;
|
|
2860
|
-
if (config.monitoring.triage?.enabled && telegram) {
|
|
2866
|
+
if (config.monitoring.triage?.enabled && (telegram || _slackAdapter)) {
|
|
2861
2867
|
triageNurse = new StallTriageNurse({
|
|
2862
2868
|
captureSessionOutput: (name, lines) => sessionManager.captureOutput(name, lines),
|
|
2863
2869
|
isSessionAlive: (name) => sessionManager.isSessionAlive(name),
|
|
2864
2870
|
sendKey: (name, key) => sessionManager.sendKey(name, key),
|
|
2865
2871
|
sendInput: (name, text) => sessionManager.sendInput(name, text),
|
|
2866
2872
|
getTopicHistory: (topicId, limit) => {
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
timestamp:
|
|
2872
|
-
}
|
|
2873
|
+
// Check if this is a Slack synthetic ID
|
|
2874
|
+
const slackChId = slackProxyChannelMap.get(topicId);
|
|
2875
|
+
if (slackChId && _slackAdapter) {
|
|
2876
|
+
const msgs = _slackAdapter.getChannelMessages(slackChId, limit);
|
|
2877
|
+
return msgs.map(m => ({ text: m.text, fromUser: true, timestamp: new Date(parseFloat(m.ts) * 1000).toISOString() }));
|
|
2878
|
+
}
|
|
2879
|
+
if (telegram) {
|
|
2880
|
+
const entries = telegram.getTopicHistory(topicId, limit);
|
|
2881
|
+
return entries.map(e => ({ text: e.text, fromUser: e.fromUser, timestamp: e.timestamp }));
|
|
2882
|
+
}
|
|
2883
|
+
return [];
|
|
2884
|
+
},
|
|
2885
|
+
sendToTopic: async (topicId, text) => {
|
|
2886
|
+
const slackChId = slackProxyChannelMap.get(topicId);
|
|
2887
|
+
if (slackChId && _slackAdapter) {
|
|
2888
|
+
await _slackAdapter.sendToChannel(slackChId, text);
|
|
2889
|
+
return;
|
|
2890
|
+
}
|
|
2891
|
+
if (telegram)
|
|
2892
|
+
await telegram.sendToTopic(topicId, text);
|
|
2893
|
+
},
|
|
2894
|
+
respawnSession: (name, topicId, options) => {
|
|
2895
|
+
if (telegram) {
|
|
2896
|
+
return respawnSessionForTopic(sessionManager, telegram, name, topicId, undefined, topicMemory, undefined, undefined, options);
|
|
2897
|
+
}
|
|
2898
|
+
// Slack respawn: kill and let next message trigger fresh session
|
|
2899
|
+
const stuckSession = sessionManager.listRunningSessions().find(s => s.tmuxSession === name);
|
|
2900
|
+
if (stuckSession)
|
|
2901
|
+
sessionManager.killSession(stuckSession.id);
|
|
2902
|
+
return Promise.resolve();
|
|
2903
|
+
},
|
|
2904
|
+
clearStallForTopic: (topicId) => {
|
|
2905
|
+
const slackChId = slackProxyChannelMap.get(topicId);
|
|
2906
|
+
if (slackChId && _slackAdapter) {
|
|
2907
|
+
_slackAdapter.clearStallTracking(slackChId);
|
|
2908
|
+
return;
|
|
2909
|
+
}
|
|
2910
|
+
if (telegram)
|
|
2911
|
+
telegram.clearStallTracking(topicId);
|
|
2873
2912
|
},
|
|
2874
|
-
sendToTopic: (topicId, text) => telegram.sendToTopic(topicId, text),
|
|
2875
|
-
respawnSession: (name, topicId, options) => respawnSessionForTopic(sessionManager, telegram, name, topicId, undefined, topicMemory, undefined, undefined, options),
|
|
2876
|
-
clearStallForTopic: (topicId) => telegram.clearStallTracking(topicId),
|
|
2877
2913
|
}, {
|
|
2878
2914
|
config: config.monitoring.triage,
|
|
2879
2915
|
state,
|
|
2880
2916
|
intelligence: sharedIntelligence,
|
|
2881
2917
|
});
|
|
2882
|
-
// Wire nurse into
|
|
2918
|
+
// Wire nurse into stall detection — both Telegram and Slack
|
|
2883
2919
|
// Note: presenceProxy may be set later — use late-binding check
|
|
2884
|
-
|
|
2920
|
+
const stallTriageHandler = async (topicId, sessionName, messageText, injectedAt) => {
|
|
2885
2921
|
// If PresenceProxy Tier 3 is actively handling this topic, defer to it
|
|
2886
2922
|
if (presenceProxy) {
|
|
2887
2923
|
const proxyState = presenceProxy.getState(topicId);
|
|
@@ -2896,27 +2932,58 @@ export async function startServer(options) {
|
|
|
2896
2932
|
const result = await triageNurse.triage(topicId, sessionName, messageText, injectedAt, 'telegram_stall');
|
|
2897
2933
|
return { resolved: result.resolved };
|
|
2898
2934
|
};
|
|
2935
|
+
if (telegram) {
|
|
2936
|
+
telegram.onStallDetected = stallTriageHandler;
|
|
2937
|
+
}
|
|
2899
2938
|
console.log(pc.green(' Stall Triage Nurse enabled'));
|
|
2900
2939
|
}
|
|
2901
2940
|
// TriageOrchestrator — next-gen session recovery with scoped Claude Code sessions
|
|
2941
|
+
// Platform-aware: works with Telegram topics AND Slack channels
|
|
2902
2942
|
let triageOrchestrator;
|
|
2903
|
-
if (config.monitoring.triageOrchestrator?.enabled && telegram) {
|
|
2943
|
+
if (config.monitoring.triageOrchestrator?.enabled && (telegram || _slackAdapter)) {
|
|
2904
2944
|
triageOrchestrator = new TriageOrchestrator({
|
|
2905
2945
|
captureSessionOutput: (name, lines) => sessionManager.captureOutput(name, lines),
|
|
2906
2946
|
isSessionAlive: (name) => sessionManager.isSessionAlive(name),
|
|
2907
2947
|
sendKey: (name, key) => sessionManager.sendKey(name, key),
|
|
2908
2948
|
sendInput: (name, text) => sessionManager.sendInput(name, text),
|
|
2909
2949
|
getTopicHistory: (topicId, limit) => {
|
|
2910
|
-
const
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2950
|
+
const slackChId = slackProxyChannelMap.get(topicId);
|
|
2951
|
+
if (slackChId && _slackAdapter) {
|
|
2952
|
+
const msgs = _slackAdapter.getChannelMessages(slackChId, limit);
|
|
2953
|
+
return msgs.map(m => ({ text: m.text, fromUser: true, timestamp: new Date(parseFloat(m.ts) * 1000).toISOString() }));
|
|
2954
|
+
}
|
|
2955
|
+
if (telegram) {
|
|
2956
|
+
const entries = telegram.getTopicHistory(topicId, limit);
|
|
2957
|
+
return entries.map(e => ({ text: e.text, fromUser: e.fromUser, timestamp: e.timestamp }));
|
|
2958
|
+
}
|
|
2959
|
+
return [];
|
|
2960
|
+
},
|
|
2961
|
+
sendToTopic: async (topicId, text) => {
|
|
2962
|
+
const slackChId = slackProxyChannelMap.get(topicId);
|
|
2963
|
+
if (slackChId && _slackAdapter) {
|
|
2964
|
+
await _slackAdapter.sendToChannel(slackChId, text);
|
|
2965
|
+
return;
|
|
2966
|
+
}
|
|
2967
|
+
if (telegram)
|
|
2968
|
+
await telegram.sendToTopic(topicId, text);
|
|
2969
|
+
},
|
|
2970
|
+
respawnSession: (name, topicId, options) => {
|
|
2971
|
+
if (telegram)
|
|
2972
|
+
return respawnSessionForTopic(sessionManager, telegram, name, topicId, undefined, topicMemory, undefined, undefined, options);
|
|
2973
|
+
const stuckSession = sessionManager.listRunningSessions().find(s => s.tmuxSession === name);
|
|
2974
|
+
if (stuckSession)
|
|
2975
|
+
sessionManager.killSession(stuckSession.id);
|
|
2976
|
+
return Promise.resolve();
|
|
2977
|
+
},
|
|
2978
|
+
clearStallForTopic: (topicId) => {
|
|
2979
|
+
const slackChId = slackProxyChannelMap.get(topicId);
|
|
2980
|
+
if (slackChId && _slackAdapter) {
|
|
2981
|
+
_slackAdapter.clearStallTracking(slackChId);
|
|
2982
|
+
return;
|
|
2983
|
+
}
|
|
2984
|
+
if (telegram)
|
|
2985
|
+
telegram.clearStallTracking(topicId);
|
|
2916
2986
|
},
|
|
2917
|
-
sendToTopic: (topicId, text) => telegram.sendToTopic(topicId, text),
|
|
2918
|
-
respawnSession: (name, topicId, options) => respawnSessionForTopic(sessionManager, telegram, name, topicId, undefined, topicMemory, undefined, undefined, options),
|
|
2919
|
-
clearStallForTopic: (topicId) => telegram.clearStallTracking(topicId),
|
|
2920
2987
|
spawnTriageSession: (name, options) => sessionManager.spawnTriageSession(name, options),
|
|
2921
2988
|
getTriageSessionUuid: (sessionName) => {
|
|
2922
2989
|
return _topicResumeMap?.findUuidForSession(sessionName) ?? undefined;
|
|
@@ -2957,33 +3024,37 @@ export async function startServer(options) {
|
|
|
2957
3024
|
state,
|
|
2958
3025
|
});
|
|
2959
3026
|
// TriageOrchestrator takes over stall detection from StallTriageNurse
|
|
2960
|
-
|
|
3027
|
+
const triageStallHandler = async (topicId, sessionName, messageText, injectedAt) => {
|
|
2961
3028
|
const result = await triageOrchestrator.activate(topicId, sessionName, 'stall_detector', messageText, injectedAt);
|
|
2962
3029
|
return { resolved: result.resolved };
|
|
2963
3030
|
};
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
origClearStall(
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
telegram.onGetTriageStatus = (topicId) => {
|
|
2972
|
-
const ts = triageOrchestrator.getTriageState(topicId);
|
|
2973
|
-
if (!ts)
|
|
2974
|
-
return null;
|
|
2975
|
-
return {
|
|
2976
|
-
active: true,
|
|
2977
|
-
classification: ts.classification,
|
|
2978
|
-
checkCount: ts.checkCount,
|
|
2979
|
-
lastCheck: new Date(ts.lastCheckAt).toISOString(),
|
|
3031
|
+
if (telegram) {
|
|
3032
|
+
telegram.onStallDetected = triageStallHandler;
|
|
3033
|
+
// Cancel triage when stall tracking clears (session responded)
|
|
3034
|
+
const origClearStall = telegram.clearStallTracking.bind(telegram);
|
|
3035
|
+
telegram.clearStallTracking = (topicId) => {
|
|
3036
|
+
origClearStall(topicId);
|
|
3037
|
+
triageOrchestrator.onTargetSessionResponded(topicId);
|
|
2980
3038
|
};
|
|
2981
|
-
|
|
3039
|
+
// Wire /triage command
|
|
3040
|
+
telegram.onGetTriageStatus = (topicId) => {
|
|
3041
|
+
const ts = triageOrchestrator.getTriageState(topicId);
|
|
3042
|
+
if (!ts)
|
|
3043
|
+
return null;
|
|
3044
|
+
return {
|
|
3045
|
+
active: true,
|
|
3046
|
+
classification: ts.classification,
|
|
3047
|
+
checkCount: ts.checkCount,
|
|
3048
|
+
lastCheck: new Date(ts.lastCheckAt).toISOString(),
|
|
3049
|
+
};
|
|
3050
|
+
};
|
|
3051
|
+
}
|
|
2982
3052
|
console.log(pc.green(' Triage Orchestrator enabled (replaces Stall Triage Nurse for stall detection)'));
|
|
2983
3053
|
}
|
|
2984
3054
|
// SessionRecovery — fast mechanical recovery (JSONL analysis, no LLM)
|
|
3055
|
+
// Platform-aware: works with Telegram topics AND Slack channels
|
|
2985
3056
|
let sessionRecovery;
|
|
2986
|
-
if (telegram) {
|
|
3057
|
+
if (telegram || _slackAdapter) {
|
|
2987
3058
|
sessionRecovery = new SessionRecovery({ enabled: true, projectDir: config.projectDir }, {
|
|
2988
3059
|
isSessionAlive: (name) => sessionManager.isSessionAlive(name),
|
|
2989
3060
|
getPanePid: (name) => {
|
|
@@ -2999,6 +3070,13 @@ export async function startServer(options) {
|
|
|
2999
3070
|
}
|
|
3000
3071
|
},
|
|
3001
3072
|
killSession: (name) => {
|
|
3073
|
+
// Route through SessionManager to fire beforeSessionKill hook
|
|
3074
|
+
const session = sessionManager.listRunningSessions().find(s => s.tmuxSession === name);
|
|
3075
|
+
if (session) {
|
|
3076
|
+
sessionManager.killSession(session.id);
|
|
3077
|
+
return;
|
|
3078
|
+
}
|
|
3079
|
+
// Fallback: direct tmux kill for untracked sessions
|
|
3002
3080
|
try {
|
|
3003
3081
|
const tmux = detectTmuxPath();
|
|
3004
3082
|
if (!tmux)
|
|
@@ -3008,32 +3086,86 @@ export async function startServer(options) {
|
|
|
3008
3086
|
catch { /* may already be dead */ }
|
|
3009
3087
|
},
|
|
3010
3088
|
respawnSession: async (topicId, _sessionName, recoveryPrompt) => {
|
|
3011
|
-
|
|
3012
|
-
|
|
3089
|
+
// Check Slack first (synthetic IDs are negative)
|
|
3090
|
+
const slackChId = slackProxyChannelMap.get(topicId);
|
|
3091
|
+
if (slackChId && _slackAdapter) {
|
|
3092
|
+
// Slack respawn: kill existing, next message triggers fresh session
|
|
3093
|
+
const session = sessionManager.listRunningSessions().find(s => s.tmuxSession === _sessionName);
|
|
3094
|
+
if (session)
|
|
3095
|
+
sessionManager.killSession(session.id);
|
|
3013
3096
|
return;
|
|
3014
|
-
|
|
3097
|
+
}
|
|
3098
|
+
if (telegram) {
|
|
3099
|
+
const targetSession = telegram.getSessionForTopic(topicId);
|
|
3100
|
+
if (!targetSession)
|
|
3101
|
+
return;
|
|
3102
|
+
await respawnSessionForTopic(sessionManager, telegram, targetSession, topicId, undefined, topicMemory, undefined, recoveryPrompt, { silent: true });
|
|
3103
|
+
}
|
|
3104
|
+
},
|
|
3105
|
+
sendToTopic: async (topicId, message) => {
|
|
3106
|
+
const slackChId = slackProxyChannelMap.get(topicId);
|
|
3107
|
+
if (slackChId && _slackAdapter) {
|
|
3108
|
+
await _slackAdapter.sendToChannel(slackChId, message);
|
|
3109
|
+
return;
|
|
3110
|
+
}
|
|
3111
|
+
if (telegram)
|
|
3112
|
+
await telegram.sendToTopic(topicId, message);
|
|
3015
3113
|
},
|
|
3016
|
-
sendToTopic: async (topicId, message) => { await telegram.sendToTopic(topicId, message); },
|
|
3017
3114
|
});
|
|
3018
3115
|
console.log(pc.green(' Session Recovery enabled (mechanical fast-path)'));
|
|
3019
3116
|
}
|
|
3020
3117
|
// SessionMonitor — proactive session health monitoring
|
|
3118
|
+
// Platform-aware: monitors both Telegram and Slack sessions
|
|
3021
3119
|
let sessionMonitor;
|
|
3022
|
-
if (telegram) {
|
|
3120
|
+
if (telegram || _slackAdapter) {
|
|
3023
3121
|
sessionMonitor = new SessionMonitor({
|
|
3024
|
-
getActiveTopicSessions: () =>
|
|
3122
|
+
getActiveTopicSessions: () => {
|
|
3123
|
+
const sessions = new Map();
|
|
3124
|
+
// Telegram topic sessions
|
|
3125
|
+
if (telegram && telegram.getActiveTopicSessions) {
|
|
3126
|
+
const telegramSessions = telegram.getActiveTopicSessions();
|
|
3127
|
+
for (const [topicId, sessionName] of telegramSessions) {
|
|
3128
|
+
sessions.set(topicId, sessionName);
|
|
3129
|
+
}
|
|
3130
|
+
}
|
|
3131
|
+
// Slack channel sessions (using synthetic IDs)
|
|
3132
|
+
if (_slackAdapter) {
|
|
3133
|
+
const registry = _slackAdapter.getChannelRegistry();
|
|
3134
|
+
for (const [channelId, entry] of Object.entries(registry)) {
|
|
3135
|
+
const syntheticId = slackChannelToSyntheticId(channelId);
|
|
3136
|
+
sessions.set(syntheticId, entry.sessionName);
|
|
3137
|
+
}
|
|
3138
|
+
}
|
|
3139
|
+
return sessions;
|
|
3140
|
+
},
|
|
3025
3141
|
captureSessionOutput: (name, lines) => sessionManager.captureOutput(name, lines),
|
|
3026
3142
|
isSessionAlive: (name) => sessionManager.isSessionAlive(name),
|
|
3027
3143
|
getTopicHistory: (topicId, limit) => {
|
|
3028
|
-
const
|
|
3029
|
-
if (
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3144
|
+
const slackChId = slackProxyChannelMap.get(topicId);
|
|
3145
|
+
if (slackChId && _slackAdapter) {
|
|
3146
|
+
const msgs = _slackAdapter.getChannelMessages(slackChId, limit);
|
|
3147
|
+
return msgs.map(m => ({ text: m.text, fromUser: true, timestamp: new Date(parseFloat(m.ts) * 1000).toISOString() }));
|
|
3148
|
+
}
|
|
3149
|
+
if (telegram) {
|
|
3150
|
+
const history = telegram.getMessageLog?.();
|
|
3151
|
+
if (!history)
|
|
3152
|
+
return [];
|
|
3153
|
+
return history
|
|
3154
|
+
.filter((m) => m.topicId === topicId)
|
|
3155
|
+
.slice(-limit)
|
|
3156
|
+
.map((m) => ({ text: m.text, fromUser: m.fromUser, timestamp: m.timestamp }));
|
|
3157
|
+
}
|
|
3158
|
+
return [];
|
|
3159
|
+
},
|
|
3160
|
+
sendToTopic: async (topicId, text) => {
|
|
3161
|
+
const slackChId = slackProxyChannelMap.get(topicId);
|
|
3162
|
+
if (slackChId && _slackAdapter) {
|
|
3163
|
+
await _slackAdapter.sendToChannel(slackChId, text);
|
|
3164
|
+
return;
|
|
3165
|
+
}
|
|
3166
|
+
if (telegram)
|
|
3167
|
+
await telegram.sendToTopic(topicId, text);
|
|
3035
3168
|
},
|
|
3036
|
-
sendToTopic: (topicId, text) => telegram.sendToTopic(topicId, text),
|
|
3037
3169
|
triggerTriage: triageOrchestrator
|
|
3038
3170
|
? async (topicId, sessionName, reason) => {
|
|
3039
3171
|
const result = await triageOrchestrator.activate(topicId, sessionName, 'watchdog', reason, Date.now());
|
|
@@ -3535,6 +3667,21 @@ export async function startServer(options) {
|
|
|
3535
3667
|
const syntheticId = slackChannelToSyntheticId(channelId);
|
|
3536
3668
|
return presenceProxy.handleCommand(syntheticId, command, parseInt(userId, 10) || 0);
|
|
3537
3669
|
};
|
|
3670
|
+
// Wire triage status for Slack !triage command
|
|
3671
|
+
if (triageOrchestrator) {
|
|
3672
|
+
_slackAdapter.onGetTriageStatus = (channelId) => {
|
|
3673
|
+
const syntheticId = slackChannelToSyntheticId(channelId);
|
|
3674
|
+
const ts = triageOrchestrator.getTriageState(syntheticId);
|
|
3675
|
+
if (!ts)
|
|
3676
|
+
return null;
|
|
3677
|
+
return {
|
|
3678
|
+
active: true,
|
|
3679
|
+
classification: ts.classification,
|
|
3680
|
+
checkCount: ts.checkCount,
|
|
3681
|
+
lastCheck: new Date(ts.lastCheckAt).toISOString(),
|
|
3682
|
+
};
|
|
3683
|
+
};
|
|
3684
|
+
}
|
|
3538
3685
|
}
|
|
3539
3686
|
console.log(pc.green(' Presence Proxy enabled (🔭 [Standby])'));
|
|
3540
3687
|
}
|