@grinev/opencode-telegram-bot 0.21.1 → 0.22.0
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/.env.example +10 -15
- package/README.md +33 -13
- package/dist/app/{start-bot-app.js → bootstrap/start-bot-app.js} +16 -15
- package/dist/{bot/utils/assistant-run-footer.js → app/formatters/assistant-run-footer-formatter.js} +1 -1
- package/dist/{summary → app/formatters}/subagent-formatter.js +8 -3
- package/dist/{summary/formatter.js → app/formatters/summary-formatter.js} +20 -132
- package/dist/{summary → app/formatters}/tool-message-batcher.js +1 -1
- package/dist/{bot/assistant-run-state.js → app/managers/assistant-run-state-manager.js} +1 -1
- package/dist/{attach/manager.js → app/managers/attach-manager.js} +1 -1
- package/dist/{background-session/tracker.js → app/managers/background-session-manager.js} +2 -2
- package/dist/{scheduled-task/foreground-state.js → app/managers/foreground-session-state-manager.js} +1 -1
- package/dist/{interaction/manager.js → app/managers/interaction-manager.js} +31 -1
- package/dist/{permission/manager.js → app/managers/permission-manager.js} +1 -1
- package/dist/{question/manager.js → app/managers/question-manager.js} +1 -1
- package/dist/{rename/manager.js → app/managers/rename-manager.js} +1 -1
- package/dist/{scheduled-task/creation-manager.js → app/managers/scheduled-task-creation-manager.js} +2 -2
- package/dist/{summary/aggregator.js → app/managers/summary-aggregation-manager.js} +177 -13
- package/dist/{agent/manager.js → app/services/agent-selection-service.js} +4 -5
- package/dist/{attach/service.js → app/services/attach-service.js} +23 -44
- package/dist/{bot/utils/busy-reconciliation.js → app/services/busy-reconciliation-service.js} +12 -7
- package/dist/app/services/command-catalog-service.js +21 -0
- package/dist/{bot/utils/external-user-input.js → app/services/external-user-input-service.js} +4 -19
- package/dist/app/services/file-browser-service.js +265 -0
- package/dist/{bot/utils/file-download.js → app/services/file-download-service.js} +14 -28
- package/dist/app/services/mcp-catalog-service.js +79 -0
- package/dist/app/services/message-history-service.js +81 -0
- package/dist/{model/capabilities.js → app/services/model-capabilities-service.js} +2 -2
- package/dist/{model/context-limit.js → app/services/model-context-limit-service.js} +4 -4
- package/dist/{model/manager.js → app/services/model-selection-service.js} +4 -4
- package/dist/{project/manager.js → app/services/project-service.js} +3 -3
- package/dist/app/services/project-switch-service.js +39 -0
- package/dist/{bot/utils/busy-guard.js → app/services/run-control-service.js} +3 -14
- package/dist/{scheduled-task/executor.js → app/services/scheduled-task-executor-service.js} +27 -12
- package/dist/{scheduled-task/runtime.js → app/services/scheduled-task-runtime-service.js} +17 -56
- package/dist/{scheduled-task/schedule-parser.js → app/services/scheduled-task-schedule-parser-service.js} +3 -3
- package/dist/{scheduled-task/session-ignore.js → app/services/scheduled-task-session-ignore-service.js} +1 -1
- package/dist/{session/cache-manager.js → app/services/session-cache-service.js} +3 -3
- package/dist/{session/manager.js → app/services/session-service.js} +1 -1
- package/dist/app/services/skills-catalog-service.js +21 -0
- package/dist/{stt/client.js → app/services/stt-service.js} +2 -2
- package/dist/{tts/client.js → app/services/tts-service.js} +68 -5
- package/dist/{variant/manager.js → app/services/variant-selection-service.js} +3 -3
- package/dist/{scheduled-task/store.js → app/stores/scheduled-task-store.js} +3 -3
- package/dist/{settings/manager.js → app/stores/settings-store.js} +49 -7
- package/dist/app/types/worktree.js +1 -0
- package/dist/bot/{handlers/agent.js → callbacks/agent-selection-callback-handler.js} +8 -57
- package/dist/bot/callbacks/callback-router.js +113 -0
- package/dist/bot/{commands/commands.js → callbacks/command-catalog-callback-handler.js} +17 -197
- package/dist/bot/{handlers/context.js → callbacks/context-control-callback-handler.js} +3 -32
- package/dist/bot/callbacks/file-browser-callback-handler.js +219 -0
- package/dist/bot/callbacks/inline-menu-cancel-callback-handler.js +32 -0
- package/dist/bot/{commands/mcps.js → callbacks/mcp-catalog-callback-handler.js} +7 -172
- package/dist/bot/{commands/messages.js → callbacks/message-history-callback-handler.js} +17 -248
- package/dist/bot/{handlers/model.js → callbacks/model-selection-callback-handler.js} +10 -71
- package/dist/bot/callbacks/permission-callback-handler.js +114 -0
- package/dist/bot/callbacks/project-callback-handler.js +79 -0
- package/dist/bot/callbacks/question-callback-handler.js +159 -0
- package/dist/bot/{commands/rename.js → callbacks/rename-callback-handler.js} +6 -34
- package/dist/bot/{commands/tasklist.js → callbacks/scheduled-task-callback-handler.js} +83 -68
- package/dist/bot/{commands/sessions.js → callbacks/session-callback-handler.js} +19 -158
- package/dist/bot/callbacks/settings-callback-handler.js +105 -0
- package/dist/bot/{commands/skills.js → callbacks/skills-catalog-callback-handler.js} +8 -188
- package/dist/bot/{handlers/variant.js → callbacks/variant-selection-callback-handler.js} +7 -69
- package/dist/bot/callbacks/worktree-callback-handler.js +97 -0
- package/dist/bot/commands/{abort.js → abort-command.js} +6 -6
- package/dist/bot/commands/command-catalog-command.js +42 -0
- package/dist/bot/commands/definitions.js +1 -1
- package/dist/bot/commands/{detach.js → detach-command.js} +8 -8
- package/dist/bot/commands/ls-command.js +48 -0
- package/dist/bot/commands/mcp-catalog-command.js +39 -0
- package/dist/bot/commands/messages-command.js +59 -0
- package/dist/bot/commands/{new.js → new-command.js} +12 -11
- package/dist/bot/commands/open-command.js +45 -0
- package/dist/bot/commands/{opencode-start.js → opencode-start-command.js} +1 -1
- package/dist/bot/commands/{opencode-stop.js → opencode-stop-command.js} +1 -1
- package/dist/bot/commands/projects-command.js +32 -0
- package/dist/bot/commands/rename-command.js +33 -0
- package/dist/bot/commands/sessions-command.js +42 -0
- package/dist/bot/commands/settings-command.js +10 -0
- package/dist/bot/commands/skills-catalog-command.js +42 -0
- package/dist/bot/commands/{start.js → start-command.js} +12 -12
- package/dist/bot/commands/{status.js → status-command.js} +15 -10
- package/dist/bot/commands/{task.js → task-command.js} +9 -81
- package/dist/bot/commands/tasklist-command.js +40 -0
- package/dist/bot/commands/worktree-command.js +47 -0
- package/dist/bot/handlers/{document.js → document-handler.js} +3 -3
- package/dist/bot/handlers/{media-group.js → media-group-handler.js} +3 -3
- package/dist/bot/handlers/photo-handler.js +44 -0
- package/dist/bot/handlers/prompt.js +17 -17
- package/dist/bot/handlers/text-message-handler.js +61 -0
- package/dist/bot/handlers/tts-response-handler.js +29 -0
- package/dist/bot/handlers/{voice.js → voice-handler.js} +6 -3
- package/dist/bot/index.js +27 -1179
- package/dist/{keyboard/manager.js → bot/keyboards/keyboard-manager.js} +6 -6
- package/dist/bot/keyboards/keyboard-types.js +1 -0
- package/dist/bot/{utils/keyboard.js → keyboards/main-reply-keyboard.js} +2 -2
- package/dist/bot/menus/agent-selection-menu.js +54 -0
- package/dist/bot/menus/command-catalog-menu.js +101 -0
- package/dist/bot/menus/context-control-menu.js +33 -0
- package/dist/bot/menus/file-browser-menu.js +265 -0
- package/dist/bot/{handlers → menus}/inline-menu.js +7 -34
- package/dist/bot/menus/mcp-catalog-menu.js +97 -0
- package/dist/bot/menus/message-history-menu.js +107 -0
- package/dist/bot/menus/model-selection-menu.js +66 -0
- package/dist/bot/menus/permission-menu.js +116 -0
- package/dist/bot/{commands/projects.js → menus/project-selection-menu.js} +5 -105
- package/dist/bot/{handlers/question.js → menus/question-menu.js} +10 -166
- package/dist/bot/menus/rename-menu.js +6 -0
- package/dist/bot/menus/scheduled-task-menu.js +42 -0
- package/dist/bot/menus/session-selection-menu.js +115 -0
- package/dist/bot/menus/settings-menu.js +52 -0
- package/dist/bot/menus/skills-catalog-menu.js +99 -0
- package/dist/bot/menus/variant-selection-menu.js +67 -0
- package/dist/bot/menus/worktree-selection-menu.js +76 -0
- package/dist/bot/{utils → messages}/assistant-rendering.js +2 -2
- package/dist/bot/messages/busy-blocked-renderer.js +11 -0
- package/dist/bot/messages/external-user-input-notification.js +22 -0
- package/dist/bot/messages/scheduled-task-delivery.js +63 -0
- package/dist/bot/{utils → messages}/send-downloaded-file.js +1 -1
- package/dist/bot/messages/summary-message-formatter.js +130 -0
- package/dist/bot/{utils → messages}/thinking-message.js +1 -4
- package/dist/bot/messages/thinking-rendering.js +66 -0
- package/dist/{interaction/guard.js → bot/middleware/interaction-guard-decision.js} +11 -4
- package/dist/bot/middleware/interaction-guard.js +2 -2
- package/dist/bot/middleware/unknown-command.js +1 -1
- package/dist/{pinned/format.js → bot/pinned/pinned-message-format.js} +1 -2
- package/dist/{pinned/manager.js → bot/pinned/pinned-message-manager.js} +10 -10
- package/dist/bot/pinned/pinned-message-types.js +1 -0
- package/dist/{summary → bot/render}/markdown-to-telegram-v2.js +2 -2
- package/dist/bot/render/types.js +1 -0
- package/dist/bot/routers/command-router.js +73 -0
- package/dist/bot/routers/message-router.js +150 -0
- package/dist/bot/services/attach-presentation.js +40 -0
- package/dist/bot/services/event-subscription-service.js +1116 -0
- package/dist/bot/services/project-switch-presentation.js +26 -0
- package/dist/bot/streaming/compact-progress-streamer.js +162 -0
- package/dist/bot/{utils → streaming}/finalize-assistant-response.js +9 -3
- package/dist/bot/streaming/response-streamer.js +16 -1
- package/dist/cli.js +4 -4
- package/dist/config.js +9 -18
- package/dist/i18n/ar.js +31 -6
- package/dist/i18n/de.js +32 -7
- package/dist/i18n/en.js +32 -7
- package/dist/i18n/es.js +32 -7
- package/dist/i18n/fr.js +32 -7
- package/dist/i18n/ru.js +32 -7
- package/dist/i18n/zh.js +32 -7
- package/dist/index.js +1 -1
- package/dist/opencode/ready-refresh.js +2 -2
- package/dist/{service → runtime/service}/manager.js +2 -2
- package/dist/runtime/service/types.js +1 -0
- package/package.json +1 -1
- package/dist/bot/commands/ls.js +0 -445
- package/dist/bot/commands/open.js +0 -319
- package/dist/bot/commands/tts.js +0 -13
- package/dist/bot/commands/worktree.js +0 -201
- package/dist/bot/handlers/permission.js +0 -235
- package/dist/bot/utils/browser-roots.js +0 -140
- package/dist/bot/utils/file-tree.js +0 -92
- package/dist/bot/utils/send-tts-response.js +0 -37
- package/dist/bot/utils/switch-project.js +0 -45
- package/dist/bot/utils/telegram-file-url.js +0 -11
- package/dist/interaction/busy.js +0 -8
- package/dist/interaction/cleanup.js +0 -32
- /package/dist/{scheduled-task/display.js → app/formatters/scheduled-task-display-formatter.js} +0 -0
- /package/dist/{bot/utils/abort-error-suppression.js → app/managers/abort-suppression-manager.js} +0 -0
- /package/dist/{external-input/suppression.js → app/managers/external-input-suppression-manager.js} +0 -0
- /package/dist/{scheduled-task/next-run.js → app/services/scheduled-task-next-run-service.js} +0 -0
- /package/dist/{git/worktree.js → app/services/worktree-service.js} +0 -0
- /package/dist/{agent/types.js → app/types/agent.js} +0 -0
- /package/dist/{interaction/types.js → app/types/interaction.js} +0 -0
- /package/dist/{model/types.js → app/types/model.js} +0 -0
- /package/dist/{keyboard/types.js → app/types/permission.js} +0 -0
- /package/dist/{permission/types.js → app/types/project.js} +0 -0
- /package/dist/{pinned/types.js → app/types/question.js} +0 -0
- /package/dist/{scheduled-task/types.js → app/types/scheduled-task.js} +0 -0
- /package/dist/{question/types.js → app/types/session.js} +0 -0
- /package/dist/{service/types.js → app/types/settings.js} +0 -0
- /package/dist/{telegram/render/types.js → app/types/summary.js} +0 -0
- /package/dist/{variant/types.js → app/types/variant.js} +0 -0
- /package/dist/bot/commands/{help.js → help-command.js} +0 -0
- /package/dist/bot/{utils → messages}/send-with-markdown-fallback.js +0 -0
- /package/dist/bot/{utils → messages}/telegram-text.js +0 -0
- /package/dist/{telegram → bot}/render/block-fallback.js +0 -0
- /package/dist/{telegram → bot}/render/block-parser.js +0 -0
- /package/dist/{telegram → bot}/render/block-renderer.js +0 -0
- /package/dist/{telegram → bot}/render/chunker.js +0 -0
- /package/dist/{telegram → bot}/render/inline-renderer.js +0 -0
- /package/dist/{telegram → bot}/render/markdown-normalizer.js +0 -0
- /package/dist/{telegram → bot}/render/pipeline.js +0 -0
- /package/dist/{telegram → bot}/render/validator.js +0 -0
- /package/dist/bot/{utils/commands.js → routers/command-utils.js} +0 -0
- /package/dist/{service/runtime.js → runtime/service/env.js} +0 -0
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
import { InlineKeyboard } from "grammy";
|
|
2
|
-
import { permissionManager } from "../../permission/manager.js";
|
|
3
|
-
import { opencodeClient } from "../../opencode/client.js";
|
|
4
|
-
import { getCurrentProject } from "../../settings/manager.js";
|
|
5
|
-
import { getCurrentSession } from "../../session/manager.js";
|
|
6
|
-
import { summaryAggregator } from "../../summary/aggregator.js";
|
|
7
|
-
import { interactionManager } from "../../interaction/manager.js";
|
|
8
|
-
import { logger } from "../../utils/logger.js";
|
|
9
|
-
import { safeBackgroundTask } from "../../utils/safe-background-task.js";
|
|
10
|
-
import { t } from "../../i18n/index.js";
|
|
11
|
-
// Permission type display names
|
|
12
|
-
const PERMISSION_NAME_KEYS = {
|
|
13
|
-
bash: "permission.name.bash",
|
|
14
|
-
edit: "permission.name.edit",
|
|
15
|
-
write: "permission.name.write",
|
|
16
|
-
read: "permission.name.read",
|
|
17
|
-
webfetch: "permission.name.webfetch",
|
|
18
|
-
websearch: "permission.name.websearch",
|
|
19
|
-
glob: "permission.name.glob",
|
|
20
|
-
grep: "permission.name.grep",
|
|
21
|
-
list: "permission.name.list",
|
|
22
|
-
task: "permission.name.task",
|
|
23
|
-
lsp: "permission.name.lsp",
|
|
24
|
-
external_directory: "permission.name.external_directory",
|
|
25
|
-
};
|
|
26
|
-
// Permission type emojis
|
|
27
|
-
const PERMISSION_EMOJIS = {
|
|
28
|
-
bash: "⚡",
|
|
29
|
-
edit: "✏️",
|
|
30
|
-
write: "📝",
|
|
31
|
-
read: "📖",
|
|
32
|
-
webfetch: "🌐",
|
|
33
|
-
websearch: "🔍",
|
|
34
|
-
glob: "📁",
|
|
35
|
-
grep: "🔎",
|
|
36
|
-
list: "📂",
|
|
37
|
-
task: "⚙️",
|
|
38
|
-
lsp: "🔧",
|
|
39
|
-
external_directory: "📁",
|
|
40
|
-
};
|
|
41
|
-
function getCallbackMessageId(ctx) {
|
|
42
|
-
const message = ctx.callbackQuery?.message;
|
|
43
|
-
if (!message || !("message_id" in message)) {
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
const messageId = message.message_id;
|
|
47
|
-
return typeof messageId === "number" ? messageId : null;
|
|
48
|
-
}
|
|
49
|
-
function clearPermissionInteraction(reason) {
|
|
50
|
-
const state = interactionManager.getSnapshot();
|
|
51
|
-
if (state?.kind === "permission") {
|
|
52
|
-
interactionManager.clear(reason);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
function syncPermissionInteractionState(metadata = {}) {
|
|
56
|
-
const pendingCount = permissionManager.getPendingCount();
|
|
57
|
-
if (pendingCount === 0) {
|
|
58
|
-
clearPermissionInteraction("permission_no_pending_requests");
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
const nextMetadata = {
|
|
62
|
-
pendingCount,
|
|
63
|
-
...metadata,
|
|
64
|
-
};
|
|
65
|
-
const state = interactionManager.getSnapshot();
|
|
66
|
-
if (state?.kind === "permission") {
|
|
67
|
-
interactionManager.transition({
|
|
68
|
-
expectedInput: "callback",
|
|
69
|
-
metadata: nextMetadata,
|
|
70
|
-
});
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
interactionManager.start({
|
|
74
|
-
kind: "permission",
|
|
75
|
-
expectedInput: "callback",
|
|
76
|
-
metadata: nextMetadata,
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
function isPermissionReply(value) {
|
|
80
|
-
return value === "once" || value === "always" || value === "reject";
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Handle permission callback from inline buttons
|
|
84
|
-
*/
|
|
85
|
-
export async function handlePermissionCallback(ctx) {
|
|
86
|
-
const data = ctx.callbackQuery?.data;
|
|
87
|
-
if (!data)
|
|
88
|
-
return false;
|
|
89
|
-
if (!data.startsWith("permission:")) {
|
|
90
|
-
return false;
|
|
91
|
-
}
|
|
92
|
-
logger.debug(`[PermissionHandler] Received callback: ${data}`);
|
|
93
|
-
if (!permissionManager.isActive()) {
|
|
94
|
-
clearPermissionInteraction("permission_inactive_callback");
|
|
95
|
-
await ctx.answerCallbackQuery({ text: t("permission.inactive_callback"), show_alert: true });
|
|
96
|
-
return true;
|
|
97
|
-
}
|
|
98
|
-
const callbackMessageId = getCallbackMessageId(ctx);
|
|
99
|
-
if (!permissionManager.isActiveMessage(callbackMessageId)) {
|
|
100
|
-
await ctx.answerCallbackQuery({ text: t("permission.inactive_callback"), show_alert: true });
|
|
101
|
-
return true;
|
|
102
|
-
}
|
|
103
|
-
const requestID = permissionManager.getRequestID(callbackMessageId);
|
|
104
|
-
if (!requestID) {
|
|
105
|
-
await ctx.answerCallbackQuery({ text: t("permission.inactive_callback"), show_alert: true });
|
|
106
|
-
return true;
|
|
107
|
-
}
|
|
108
|
-
const parts = data.split(":");
|
|
109
|
-
const action = parts[1];
|
|
110
|
-
if (!isPermissionReply(action)) {
|
|
111
|
-
await ctx.answerCallbackQuery({
|
|
112
|
-
text: t("permission.processing_error_callback"),
|
|
113
|
-
show_alert: true,
|
|
114
|
-
});
|
|
115
|
-
return true;
|
|
116
|
-
}
|
|
117
|
-
try {
|
|
118
|
-
await handlePermissionReply(ctx, action, requestID, callbackMessageId);
|
|
119
|
-
}
|
|
120
|
-
catch (err) {
|
|
121
|
-
logger.error("[PermissionHandler] Error handling callback:", err);
|
|
122
|
-
await ctx.answerCallbackQuery({
|
|
123
|
-
text: t("permission.processing_error_callback"),
|
|
124
|
-
show_alert: true,
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
return true;
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Handle permission reply (once/always/reject)
|
|
131
|
-
*/
|
|
132
|
-
async function handlePermissionReply(ctx, reply, requestID, callbackMessageId) {
|
|
133
|
-
const currentProject = getCurrentProject();
|
|
134
|
-
const currentSession = getCurrentSession();
|
|
135
|
-
const chatId = ctx.chat?.id;
|
|
136
|
-
const directory = currentSession?.directory ?? currentProject?.worktree;
|
|
137
|
-
if (!directory || !chatId) {
|
|
138
|
-
permissionManager.clear();
|
|
139
|
-
clearPermissionInteraction("permission_invalid_runtime_context");
|
|
140
|
-
await ctx.answerCallbackQuery({
|
|
141
|
-
text: t("permission.no_active_request_callback"),
|
|
142
|
-
show_alert: true,
|
|
143
|
-
});
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
// Reply labels for user feedback
|
|
147
|
-
const replyLabels = {
|
|
148
|
-
once: t("permission.reply.once"),
|
|
149
|
-
always: t("permission.reply.always"),
|
|
150
|
-
reject: t("permission.reply.reject"),
|
|
151
|
-
};
|
|
152
|
-
await ctx.answerCallbackQuery({ text: replyLabels[reply] });
|
|
153
|
-
// Delete the permission message
|
|
154
|
-
await ctx.deleteMessage().catch(() => { });
|
|
155
|
-
// Stop typing indicator since we're responding
|
|
156
|
-
summaryAggregator.stopTypingIndicator();
|
|
157
|
-
logger.info(`[PermissionHandler] Sending permission reply: ${reply}, requestID=${requestID}`);
|
|
158
|
-
// CRITICAL: Fire-and-forget! Do not block the handler
|
|
159
|
-
safeBackgroundTask({
|
|
160
|
-
taskName: "permission.reply",
|
|
161
|
-
task: () => opencodeClient.permission.reply({
|
|
162
|
-
requestID,
|
|
163
|
-
directory,
|
|
164
|
-
reply,
|
|
165
|
-
}),
|
|
166
|
-
onSuccess: ({ error }) => {
|
|
167
|
-
if (error) {
|
|
168
|
-
logger.error("[PermissionHandler] Failed to send permission reply:", error);
|
|
169
|
-
if (ctx.api && chatId) {
|
|
170
|
-
void ctx.api.sendMessage(chatId, t("permission.send_reply_error")).catch(() => { });
|
|
171
|
-
}
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
logger.info("[PermissionHandler] Permission reply sent successfully");
|
|
175
|
-
},
|
|
176
|
-
});
|
|
177
|
-
permissionManager.removeByMessageId(callbackMessageId);
|
|
178
|
-
if (!permissionManager.isActive()) {
|
|
179
|
-
clearPermissionInteraction("permission_replied");
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
syncPermissionInteractionState({
|
|
183
|
-
lastRepliedRequestID: requestID,
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* Show permission request message with inline buttons
|
|
188
|
-
*/
|
|
189
|
-
export async function showPermissionRequest(bot, chatId, request) {
|
|
190
|
-
logger.debug(`[PermissionHandler] Showing permission request: ${request.permission}`);
|
|
191
|
-
const text = formatPermissionText(request);
|
|
192
|
-
const keyboard = buildPermissionKeyboard();
|
|
193
|
-
try {
|
|
194
|
-
const message = await bot.sendMessage(chatId, text, {
|
|
195
|
-
reply_markup: keyboard,
|
|
196
|
-
});
|
|
197
|
-
logger.debug(`[PermissionHandler] Message sent, messageId=${message.message_id}`);
|
|
198
|
-
permissionManager.startPermission(request, message.message_id);
|
|
199
|
-
syncPermissionInteractionState({
|
|
200
|
-
requestID: request.id,
|
|
201
|
-
messageId: message.message_id,
|
|
202
|
-
});
|
|
203
|
-
summaryAggregator.stopTypingIndicator();
|
|
204
|
-
}
|
|
205
|
-
catch (err) {
|
|
206
|
-
logger.error("[PermissionHandler] Failed to send permission message:", err);
|
|
207
|
-
throw err;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* Format permission request text
|
|
212
|
-
*/
|
|
213
|
-
function formatPermissionText(request) {
|
|
214
|
-
const emoji = PERMISSION_EMOJIS[request.permission] || "🔐";
|
|
215
|
-
const nameKey = PERMISSION_NAME_KEYS[request.permission];
|
|
216
|
-
const name = nameKey ? t(nameKey) : request.permission;
|
|
217
|
-
let text = t("permission.header", { emoji, name });
|
|
218
|
-
// Show patterns (commands/files)
|
|
219
|
-
if (request.patterns.length > 0) {
|
|
220
|
-
request.patterns.forEach((pattern) => {
|
|
221
|
-
text += `• ${pattern}\n`;
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
return text;
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Build inline keyboard with permission buttons
|
|
228
|
-
*/
|
|
229
|
-
function buildPermissionKeyboard() {
|
|
230
|
-
const keyboard = new InlineKeyboard();
|
|
231
|
-
keyboard.text(t("permission.button.allow"), "permission:once").row();
|
|
232
|
-
keyboard.text(t("permission.button.always"), "permission:always").row();
|
|
233
|
-
keyboard.text(t("permission.button.reject"), "permission:reject");
|
|
234
|
-
return keyboard;
|
|
235
|
-
}
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { realpath } from "node:fs/promises";
|
|
3
|
-
import os from "node:os";
|
|
4
|
-
import { logger } from "../../utils/logger.js";
|
|
5
|
-
/**
|
|
6
|
-
* Allowed root directories for the `/open` command.
|
|
7
|
-
*
|
|
8
|
-
* Configured via `OPEN_BROWSER_ROOTS` env var (comma-separated absolute paths).
|
|
9
|
-
* Defaults to `[os.homedir()]` when the variable is not set.
|
|
10
|
-
*
|
|
11
|
-
* All navigation in the directory browser is restricted to stay within one
|
|
12
|
-
* of the configured roots. This prevents the bot from browsing arbitrary
|
|
13
|
-
* locations on the filesystem.
|
|
14
|
-
*/
|
|
15
|
-
let resolvedRoots = null;
|
|
16
|
-
function isWindows() {
|
|
17
|
-
return process.platform === "win32";
|
|
18
|
-
}
|
|
19
|
-
function resolveConfiguredPath(p) {
|
|
20
|
-
return path.resolve(expandTilde(p));
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Expand a leading `~` or `~/` to the user's home directory.
|
|
24
|
-
* Does not handle `~user/` syntax — only the current user's home.
|
|
25
|
-
*/
|
|
26
|
-
function expandTilde(p) {
|
|
27
|
-
if (p === "~") {
|
|
28
|
-
return os.homedir();
|
|
29
|
-
}
|
|
30
|
-
if (p.startsWith("~/") || p.startsWith("~\\")) {
|
|
31
|
-
return path.join(os.homedir(), p.slice(2));
|
|
32
|
-
}
|
|
33
|
-
return p;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Normalize a path for comparison: expand tilde, resolve, then lowercase on Windows.
|
|
37
|
-
*/
|
|
38
|
-
function normalizePath(p) {
|
|
39
|
-
const resolved = resolveConfiguredPath(p);
|
|
40
|
-
return isWindows() ? resolved.toLowerCase() : resolved;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Initialize (or re-initialize) the allowed browser roots from the raw
|
|
44
|
-
* env string. Each entry is resolved to an absolute path via `path.resolve`.
|
|
45
|
-
*
|
|
46
|
-
* Entries that cannot be resolved are logged and skipped.
|
|
47
|
-
*/
|
|
48
|
-
export function initBrowserRoots(raw) {
|
|
49
|
-
if (!raw || raw.trim() === "") {
|
|
50
|
-
resolvedRoots = [resolveConfiguredPath(os.homedir())];
|
|
51
|
-
logger.debug(`[BrowserRoots] No OPEN_BROWSER_ROOTS configured, defaulting to home: ${resolvedRoots[0]}`);
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
const entries = raw
|
|
55
|
-
.split(",")
|
|
56
|
-
.map((s) => s.trim())
|
|
57
|
-
.filter((s) => s.length > 0);
|
|
58
|
-
const roots = [];
|
|
59
|
-
for (const entry of entries) {
|
|
60
|
-
roots.push(resolveConfiguredPath(entry));
|
|
61
|
-
}
|
|
62
|
-
if (roots.length === 0) {
|
|
63
|
-
resolvedRoots = [resolveConfiguredPath(os.homedir())];
|
|
64
|
-
logger.warn("[BrowserRoots] All configured roots were invalid, falling back to home directory");
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
resolvedRoots = roots;
|
|
68
|
-
logger.info(`[BrowserRoots] Configured roots: ${roots.join(", ")}`);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Return the configured browser roots. Lazily initializes from env if
|
|
73
|
-
* `initBrowserRoots` was never called.
|
|
74
|
-
*/
|
|
75
|
-
export function getBrowserRoots() {
|
|
76
|
-
if (resolvedRoots === null) {
|
|
77
|
-
initBrowserRoots(process.env.OPEN_BROWSER_ROOTS);
|
|
78
|
-
}
|
|
79
|
-
return resolvedRoots;
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Return the original (non-normalized) root paths for display/navigation.
|
|
83
|
-
* On Windows the display roots are lowercased because `normalizePath` is
|
|
84
|
-
* used during init — this is acceptable for button labels.
|
|
85
|
-
*/
|
|
86
|
-
export function getBrowserRootPaths() {
|
|
87
|
-
return getBrowserRoots();
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Check whether a target path is inside one of the allowed roots.
|
|
91
|
-
*
|
|
92
|
-
* Uses `path.resolve` on the target for consistent comparison, then
|
|
93
|
-
* checks that the target equals a root or is a descendant (starts with
|
|
94
|
-
* root + separator).
|
|
95
|
-
*
|
|
96
|
-
* For full symlink-proof validation, callers can optionally resolve the
|
|
97
|
-
* target with `fs.realpath` before calling this function.
|
|
98
|
-
*/
|
|
99
|
-
export function isWithinAllowedRoot(targetPath) {
|
|
100
|
-
const normalizedTarget = normalizePath(targetPath);
|
|
101
|
-
const roots = getBrowserRoots();
|
|
102
|
-
for (const root of roots) {
|
|
103
|
-
const normalizedRoot = normalizePath(root);
|
|
104
|
-
if (normalizedTarget === normalizedRoot) {
|
|
105
|
-
return true;
|
|
106
|
-
}
|
|
107
|
-
// Check both separators — `path.sep` is always `/` on Unix but a
|
|
108
|
-
// lowercased Windows path may contain either `\` or `/`.
|
|
109
|
-
if (normalizedTarget.startsWith(normalizedRoot + "/") ||
|
|
110
|
-
normalizedTarget.startsWith(normalizedRoot + "\\")) {
|
|
111
|
-
return true;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return false;
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Like `isWithinAllowedRoot` but resolves symlinks first using `realpath`.
|
|
118
|
-
* Falls back to the plain path if `realpath` fails (e.g. ENOENT).
|
|
119
|
-
*/
|
|
120
|
-
export async function isWithinAllowedRootSafe(targetPath) {
|
|
121
|
-
let resolved = targetPath;
|
|
122
|
-
try {
|
|
123
|
-
resolved = await realpath(targetPath);
|
|
124
|
-
}
|
|
125
|
-
catch {
|
|
126
|
-
// Path doesn't exist yet or can't be resolved — use as-is
|
|
127
|
-
}
|
|
128
|
-
return isWithinAllowedRoot(resolved);
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Check whether a path is exactly one of the allowed roots (not a descendant).
|
|
132
|
-
*/
|
|
133
|
-
export function isAllowedRoot(targetPath) {
|
|
134
|
-
const normalizedTarget = normalizePath(targetPath);
|
|
135
|
-
return getBrowserRoots().some((root) => normalizePath(root) === normalizedTarget);
|
|
136
|
-
}
|
|
137
|
-
/** Reset state — for testing only. */
|
|
138
|
-
export function __resetBrowserRootsForTests() {
|
|
139
|
-
resolvedRoots = null;
|
|
140
|
-
}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { promises as fs } from "node:fs";
|
|
2
|
-
import os from "node:os";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { t } from "../../i18n/index.js";
|
|
5
|
-
export const MAX_ENTRIES_PER_PAGE = 8;
|
|
6
|
-
export function getHomeDirectory() {
|
|
7
|
-
return os.homedir();
|
|
8
|
-
}
|
|
9
|
-
export function pathToDisplayPath(absolutePath) {
|
|
10
|
-
const home = getHomeDirectory();
|
|
11
|
-
if (absolutePath === home) {
|
|
12
|
-
return "~";
|
|
13
|
-
}
|
|
14
|
-
if (absolutePath.startsWith(home + path.sep)) {
|
|
15
|
-
return "~" + absolutePath.slice(home.length);
|
|
16
|
-
}
|
|
17
|
-
return absolutePath;
|
|
18
|
-
}
|
|
19
|
-
export async function scanDirectory(dirPath, page = 0) {
|
|
20
|
-
try {
|
|
21
|
-
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
22
|
-
const subdirs = [];
|
|
23
|
-
for (const entry of entries) {
|
|
24
|
-
if (entry.isDirectory() && !entry.name.startsWith(".")) {
|
|
25
|
-
subdirs.push({
|
|
26
|
-
name: entry.name,
|
|
27
|
-
fullPath: path.join(dirPath, entry.name),
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
subdirs.sort((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: "base" }));
|
|
32
|
-
const parentPath = path.dirname(dirPath);
|
|
33
|
-
const hasParent = dirPath !== path.parse(dirPath).root;
|
|
34
|
-
// Clamp page to valid range so stale or crafted callbacks never produce
|
|
35
|
-
// an out-of-bounds page indicator like "(4/2)".
|
|
36
|
-
const totalPages = Math.max(1, Math.ceil(subdirs.length / MAX_ENTRIES_PER_PAGE));
|
|
37
|
-
const safePage = Math.max(0, Math.min(page, totalPages - 1));
|
|
38
|
-
const start = safePage * MAX_ENTRIES_PER_PAGE;
|
|
39
|
-
const pageEntries = subdirs.slice(start, start + MAX_ENTRIES_PER_PAGE);
|
|
40
|
-
return {
|
|
41
|
-
entries: pageEntries,
|
|
42
|
-
totalCount: subdirs.length,
|
|
43
|
-
page: safePage,
|
|
44
|
-
currentPath: dirPath,
|
|
45
|
-
displayPath: pathToDisplayPath(dirPath),
|
|
46
|
-
hasParent,
|
|
47
|
-
parentPath: hasParent ? parentPath : null,
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
catch (error) {
|
|
51
|
-
if (error instanceof Error) {
|
|
52
|
-
if ("code" in error) {
|
|
53
|
-
const code = error.code;
|
|
54
|
-
if (code === "ENOENT" || code === "ELOOP") {
|
|
55
|
-
return { error: `Directory not found: ${dirPath}`, code: "ENOENT" };
|
|
56
|
-
}
|
|
57
|
-
if (code === "EACCES" || code === "EPERM") {
|
|
58
|
-
return { error: `Permission denied: ${dirPath}`, code: "EACCES" };
|
|
59
|
-
}
|
|
60
|
-
if (code === "ENOTDIR") {
|
|
61
|
-
return { error: `Not a directory: ${dirPath}`, code: "ENOTDIR" };
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return {
|
|
66
|
-
error: error instanceof Error ? error.message : "Unknown error",
|
|
67
|
-
code: "UNKNOWN",
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
export function buildEntryLabel(entry) {
|
|
72
|
-
return `📁 ${entry.name}`;
|
|
73
|
-
}
|
|
74
|
-
export function buildTreeHeader(displayPath, totalCount, page, totalPages) {
|
|
75
|
-
let header = `📂 ${displayPath}`;
|
|
76
|
-
if (totalPages > 1) {
|
|
77
|
-
header += ` (${page + 1}/${totalPages})`;
|
|
78
|
-
}
|
|
79
|
-
if (totalCount === 0) {
|
|
80
|
-
header += `\n${t("open.no_subfolders")}`;
|
|
81
|
-
}
|
|
82
|
-
else if (totalCount === 1) {
|
|
83
|
-
header += `\n${t("open.subfolder_count", { count: String(totalCount) })}`;
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
header += `\n${t("open.subfolders_count", { count: String(totalCount) })}`;
|
|
87
|
-
}
|
|
88
|
-
return header;
|
|
89
|
-
}
|
|
90
|
-
export function isScanError(result) {
|
|
91
|
-
return "error" in result;
|
|
92
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { InputFile } from "grammy";
|
|
2
|
-
import { consumePromptResponseMode } from "../handlers/prompt.js";
|
|
3
|
-
import { isTtsConfigured, synthesizeSpeech } from "../../tts/client.js";
|
|
4
|
-
import { t } from "../../i18n/index.js";
|
|
5
|
-
import { logger } from "../../utils/logger.js";
|
|
6
|
-
const MAX_TTS_INPUT_CHARS = 4_000;
|
|
7
|
-
export async function sendTtsResponseForSession({ api, sessionId, chatId, text, consumeResponseMode: consumeResponseModeImpl = consumePromptResponseMode, isTtsConfigured: isTtsConfiguredImpl = isTtsConfigured, synthesizeSpeech: synthesizeSpeechImpl = synthesizeSpeech, }) {
|
|
8
|
-
const responseMode = consumeResponseModeImpl(sessionId);
|
|
9
|
-
if (responseMode !== "text_and_tts") {
|
|
10
|
-
return false;
|
|
11
|
-
}
|
|
12
|
-
const normalizedText = text.trim();
|
|
13
|
-
if (!normalizedText) {
|
|
14
|
-
return false;
|
|
15
|
-
}
|
|
16
|
-
if (!isTtsConfiguredImpl()) {
|
|
17
|
-
logger.info(`[TTS] Skipping audio reply for session ${sessionId}: TTS is not configured`);
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
if (normalizedText.length > MAX_TTS_INPUT_CHARS) {
|
|
21
|
-
logger.warn(`[TTS] Skipping audio reply for session ${sessionId}: text length ${normalizedText.length} exceeds limit ${MAX_TTS_INPUT_CHARS}`);
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
try {
|
|
25
|
-
const speech = await synthesizeSpeechImpl(normalizedText);
|
|
26
|
-
await api.sendAudio(chatId, new InputFile(speech.buffer, speech.filename));
|
|
27
|
-
logger.info(`[TTS] Sent audio reply for session ${sessionId}`);
|
|
28
|
-
return true;
|
|
29
|
-
}
|
|
30
|
-
catch (error) {
|
|
31
|
-
logger.warn(`[TTS] Failed to send audio reply for session ${sessionId}`, error);
|
|
32
|
-
await api.sendMessage(chatId, t("tts.failed")).catch((sendError) => {
|
|
33
|
-
logger.warn(`[TTS] Failed to send audio error message for session ${sessionId}`, sendError);
|
|
34
|
-
});
|
|
35
|
-
return false;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { setCurrentProject } from "../../settings/manager.js";
|
|
2
|
-
import { clearSession } from "../../session/manager.js";
|
|
3
|
-
import { summaryAggregator } from "../../summary/aggregator.js";
|
|
4
|
-
import { pinnedMessageManager } from "../../pinned/manager.js";
|
|
5
|
-
import { keyboardManager } from "../../keyboard/manager.js";
|
|
6
|
-
import { detachAttachedSession } from "../../attach/service.js";
|
|
7
|
-
import { stopEventListening } from "../../opencode/events.js";
|
|
8
|
-
import { backgroundSessionTracker } from "../../background-session/tracker.js";
|
|
9
|
-
import { getStoredAgent, resolveProjectAgent } from "../../agent/manager.js";
|
|
10
|
-
import { getStoredModel } from "../../model/manager.js";
|
|
11
|
-
import { formatVariantForButton } from "../../variant/manager.js";
|
|
12
|
-
import { clearAllInteractionState } from "../../interaction/cleanup.js";
|
|
13
|
-
import { createMainKeyboard } from "./keyboard.js";
|
|
14
|
-
import { logger } from "../../utils/logger.js";
|
|
15
|
-
import { config } from "../../config.js";
|
|
16
|
-
export async function switchToProject(ctx, project, reason, options = {}) {
|
|
17
|
-
detachAttachedSession(reason);
|
|
18
|
-
stopEventListening();
|
|
19
|
-
backgroundSessionTracker.clear();
|
|
20
|
-
setCurrentProject(project);
|
|
21
|
-
clearSession();
|
|
22
|
-
summaryAggregator.clear();
|
|
23
|
-
clearAllInteractionState(reason);
|
|
24
|
-
try {
|
|
25
|
-
await pinnedMessageManager.clear();
|
|
26
|
-
}
|
|
27
|
-
catch (err) {
|
|
28
|
-
logger.error("[Bot] Error clearing pinned message:", err);
|
|
29
|
-
}
|
|
30
|
-
if (ctx.chat) {
|
|
31
|
-
keyboardManager.initialize(ctx.api, ctx.chat.id);
|
|
32
|
-
}
|
|
33
|
-
await pinnedMessageManager.refreshContextLimit();
|
|
34
|
-
const contextLimit = pinnedMessageManager.getContextLimit();
|
|
35
|
-
keyboardManager.updateContext(0, contextLimit);
|
|
36
|
-
const currentAgent = await resolveProjectAgent(getStoredAgent());
|
|
37
|
-
const currentModel = getStoredModel();
|
|
38
|
-
const contextInfo = { tokensUsed: 0, tokensLimit: contextLimit };
|
|
39
|
-
const variantName = formatVariantForButton(currentModel.variant || "default");
|
|
40
|
-
keyboardManager.updateAgent(currentAgent);
|
|
41
|
-
if (config.bot.trackBackgroundSessions && options.ensureEventSubscription) {
|
|
42
|
-
await options.ensureEventSubscription(project.worktree);
|
|
43
|
-
}
|
|
44
|
-
return createMainKeyboard(currentAgent, currentModel, contextInfo, variantName);
|
|
45
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { config } from "../../config.js";
|
|
2
|
-
const DEFAULT_TELEGRAM_API_ROOT = "https://api.telegram.org";
|
|
3
|
-
export function telegramFileUrlBase() {
|
|
4
|
-
const apiRoot = config.telegram.apiRoot
|
|
5
|
-
? config.telegram.apiRoot.replace(/\/+$/, "")
|
|
6
|
-
: DEFAULT_TELEGRAM_API_ROOT;
|
|
7
|
-
return `${apiRoot}/file/bot`;
|
|
8
|
-
}
|
|
9
|
-
export function buildTelegramFileUrl(filePath) {
|
|
10
|
-
return `${telegramFileUrlBase()}${config.telegram.token}/${filePath}`;
|
|
11
|
-
}
|
package/dist/interaction/busy.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export const BUSY_ALLOWED_COMMANDS = ["/abort", "/detach", "/status", "/help"];
|
|
2
|
-
const BUSY_ALLOWED_COMMAND_SET = new Set(BUSY_ALLOWED_COMMANDS);
|
|
3
|
-
export function isBusyAllowedCommand(command) {
|
|
4
|
-
return Boolean(command && BUSY_ALLOWED_COMMAND_SET.has(command));
|
|
5
|
-
}
|
|
6
|
-
export function allowsBusyInteraction(kind) {
|
|
7
|
-
return kind === "question" || kind === "permission";
|
|
8
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { permissionManager } from "../permission/manager.js";
|
|
2
|
-
import { questionManager } from "../question/manager.js";
|
|
3
|
-
import { renameManager } from "../rename/manager.js";
|
|
4
|
-
import { taskCreationManager } from "../scheduled-task/creation-manager.js";
|
|
5
|
-
import { interactionManager } from "./manager.js";
|
|
6
|
-
import { logger } from "../utils/logger.js";
|
|
7
|
-
export function clearAllInteractionState(reason) {
|
|
8
|
-
const questionActive = questionManager.isActive();
|
|
9
|
-
const permissionActive = permissionManager.isActive();
|
|
10
|
-
const renameActive = renameManager.isWaitingForName();
|
|
11
|
-
const taskCreationActive = taskCreationManager.isActive();
|
|
12
|
-
const interactionSnapshot = interactionManager.getSnapshot();
|
|
13
|
-
questionManager.clear();
|
|
14
|
-
permissionManager.clear();
|
|
15
|
-
renameManager.clear();
|
|
16
|
-
taskCreationManager.clear();
|
|
17
|
-
interactionManager.clear(reason);
|
|
18
|
-
const hasAnyActiveState = questionActive ||
|
|
19
|
-
permissionActive ||
|
|
20
|
-
renameActive ||
|
|
21
|
-
taskCreationActive ||
|
|
22
|
-
interactionSnapshot !== null;
|
|
23
|
-
const message = `[InteractionCleanup] Cleared state: reason=${reason}, ` +
|
|
24
|
-
`questionActive=${questionActive}, permissionActive=${permissionActive}, ` +
|
|
25
|
-
`renameActive=${renameActive}, taskCreationActive=${taskCreationActive}, ` +
|
|
26
|
-
`interactionKind=${interactionSnapshot?.kind || "none"}`;
|
|
27
|
-
if (hasAnyActiveState) {
|
|
28
|
-
logger.info(message);
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
logger.debug(message);
|
|
32
|
-
}
|
/package/dist/{scheduled-task/display.js → app/formatters/scheduled-task-display-formatter.js}
RENAMED
|
File without changes
|
/package/dist/{bot/utils/abort-error-suppression.js → app/managers/abort-suppression-manager.js}
RENAMED
|
File without changes
|
/package/dist/{external-input/suppression.js → app/managers/external-input-suppression-manager.js}
RENAMED
|
File without changes
|
/package/dist/{scheduled-task/next-run.js → app/services/scheduled-task-next-run-service.js}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|