opencode-tbot 0.1.25 → 0.1.27

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/README.ja.md CHANGED
@@ -80,6 +80,11 @@ npm exec --package opencode-tbot@latest opencode-tbot -- update
80
80
  "state": {
81
81
  "path": "./data/opencode-tbot.state.json"
82
82
  },
83
+ "prompt": {
84
+ "waitTimeoutMs": 1800000,
85
+ "pollRequestTimeoutMs": 15000,
86
+ "recoveryInactivityTimeoutMs": 120000
87
+ },
83
88
  "logLevel": "info"
84
89
  }
85
90
  ```
package/README.md CHANGED
@@ -81,6 +81,11 @@ Legacy `openrouter` voice-transcription settings are ignored at runtime. When th
81
81
  "state": {
82
82
  "path": "./data/opencode-tbot.state.json"
83
83
  },
84
+ "prompt": {
85
+ "waitTimeoutMs": 1800000,
86
+ "pollRequestTimeoutMs": 15000,
87
+ "recoveryInactivityTimeoutMs": 120000
88
+ },
84
89
  "logLevel": "info"
85
90
  }
86
91
  ```
@@ -93,11 +98,16 @@ Legacy `openrouter` voice-transcription settings are ignored at runtime. When th
93
98
  | `telegram.allowedChatIds` | No | `[]` | Allowed Telegram chat IDs. If empty, the bot accepts messages from any chat. |
94
99
  | `telegram.apiRoot` | No | `https://api.telegram.org` | Telegram Bot API base URL. Useful for tests or self-hosted gateways. |
95
100
  | `state.path` | No | `./data/opencode-tbot.state.json` | JSON state file path, resolved relative to the current OpenCode worktree. |
101
+ | `prompt.waitTimeoutMs` | No | `1800000` | Maximum total wait for one async prompt lifecycle before the plugin stops waiting for OpenCode recovery. |
102
+ | `prompt.pollRequestTimeoutMs` | No | `15000` | Timeout for each individual recovery poll request to OpenCode. |
103
+ | `prompt.recoveryInactivityTimeoutMs` | No | `120000` | Recovery timeout that only applies when prompt progress stops advancing. |
96
104
  | `logLevel` | No | `info` | Plugin log level. Logs are emitted through `client.app.log()`. |
97
105
 
98
106
  ### Notes
99
107
 
100
108
  - `state.path` is resolved relative to the current OpenCode worktree.
109
+ - Telegram prompt handling is async-first: the plugin submits `session.promptAsync()` and then recovers the reply from session messages and session status.
110
+ - `prompt.waitTimeoutMs` is the total safety cap; `prompt.recoveryInactivityTimeoutMs` only applies when OpenCode stops making progress.
101
111
  - If `telegram.allowedChatIds` is left empty, the bot accepts messages from any chat. Restrict it in production.
102
112
  - Permission approvals and session notifications are handled through plugin hooks.
103
113
  - `/language` currently supports English, Simplified Chinese, and Japanese.
@@ -117,7 +127,7 @@ Legacy `openrouter` voice-transcription settings are ignored at runtime. When th
117
127
  - `/new [title]` create a new OpenCode session
118
128
  - `/agents` or `/agent` list available agents and switch the active one
119
129
  - `/sessions` list available sessions and switch the active one
120
- - `/cancel` cancel session rename or abort the running request for the current session
130
+ - `/cancel` cancel session rename or abort the running request for the current session, including the local Telegram wait state
121
131
  - `/model` or `/models` list available models and switch the active one
122
132
  - `/language` switch the bot display language
123
133
 
@@ -126,6 +136,7 @@ Message handling:
126
136
  - Non-command text is treated as a prompt and sent to OpenCode.
127
137
  - Telegram photos and image documents are forwarded as OpenCode file parts.
128
138
  - Image attachments are processed in a temporary fork of the active session so later text-only prompts stay clean.
139
+ - `/cancel` aborts both the OpenCode session and the local Telegram wait, so the next prompt can start immediately.
129
140
  - Telegram voice messages are not supported and receive a localized rejection reply.
130
141
 
131
142
  ## Development
package/README.zh-CN.md CHANGED
@@ -80,6 +80,11 @@ npm exec --package opencode-tbot@latest opencode-tbot -- update
80
80
  "state": {
81
81
  "path": "./data/opencode-tbot.state.json"
82
82
  },
83
+ "prompt": {
84
+ "waitTimeoutMs": 1800000,
85
+ "pollRequestTimeoutMs": 15000,
86
+ "recoveryInactivityTimeoutMs": 120000
87
+ },
83
88
  "logLevel": "info"
84
89
  }
85
90
  ```
@@ -92,11 +97,16 @@ npm exec --package opencode-tbot@latest opencode-tbot -- update
92
97
  | `telegram.allowedChatIds` | 否 | `[]` | 允许访问的 Telegram chat ID 数组。为空时表示接受任意 chat。 |
93
98
  | `telegram.apiRoot` | 否 | `https://api.telegram.org` | Telegram Bot API 根地址,适合测试或自托管网关。 |
94
99
  | `state.path` | 否 | `./data/opencode-tbot.state.json` | JSON 状态文件路径,相对当前 OpenCode worktree 解析。 |
100
+ | `prompt.waitTimeoutMs` | 否 | `1800000` | 单次异步 prompt 生命周期的最大等待时间;超过后插件会停止等待 OpenCode 恢复结果。 |
101
+ | `prompt.pollRequestTimeoutMs` | 否 | `15000` | 每次向 OpenCode 拉取恢复状态时的单次请求超时。 |
102
+ | `prompt.recoveryInactivityTimeoutMs` | 否 | `120000` | 仅在 prompt 长时间没有任何新进展时生效的恢复超时。 |
95
103
  | `logLevel` | 否 | `info` | 插件日志级别。日志统一通过 `client.app.log()` 上报。 |
96
104
 
97
105
  ### 说明
98
106
 
99
107
  - `state.path` 会相对当前 OpenCode worktree 解析。
108
+ - Telegram prompt 处理现在采用 async-first:插件先调用 `session.promptAsync()`,再通过会话消息和会话状态恢复最终回复。
109
+ - `prompt.waitTimeoutMs` 是整体安全上限;`prompt.recoveryInactivityTimeoutMs` 只在 OpenCode 长时间没有新进展时生效。
100
110
  - 如果 `telegram.allowedChatIds` 为空,bot 会接受任意 chat 的消息;生产环境建议显式限制。
101
111
  - 权限审批和会话通知通过插件 hook 处理。
102
112
  - `/language` 当前支持 English、简体中文、日本語。
@@ -116,7 +126,7 @@ npm exec --package opencode-tbot@latest opencode-tbot -- update
116
126
  - `/new [title]` 创建新的 OpenCode 会话
117
127
  - `/agents` 或 `/agent` 列出可用 agent 并切换当前 agent
118
128
  - `/sessions` 列出会话并切换当前会话
119
- - `/cancel` 取消会话重命名,或中止当前会话正在运行的请求
129
+ - `/cancel` 取消会话重命名,或中止当前会话正在运行的请求,并同步结束本地 Telegram 等待状态
120
130
  - `/model` 或 `/models` 列出可用模型并切换当前模型
121
131
  - `/language` 切换 bot 显示语言
122
132
 
@@ -124,6 +134,7 @@ npm exec --package opencode-tbot@latest opencode-tbot -- update
124
134
 
125
135
  - 任意非命令文本都会被当作 prompt 发送给 OpenCode。
126
136
  - Telegram 照片和图片文档会作为 OpenCode 文件片段上传。
137
+ - `/cancel` 会同时中止 OpenCode 侧会话和本地 Telegram 等待,因此下一条消息可以立即开始处理。
127
138
  - Telegram 语音消息当前不受支持,bot 会直接返回本地化拒绝提示。
128
139
 
129
140
  ## 开发
@@ -7,6 +7,9 @@ import { fileURLToPath } from "node:url";
7
7
  //#region src/app/config.ts
8
8
  var DEFAULT_STATE_FILE_PATH = "./data/opencode-tbot.state.json";
9
9
  var DEFAULT_TELEGRAM_API_ROOT = "https://api.telegram.org";
10
+ var DEFAULT_PROMPT_WAIT_TIMEOUT_MS = 18e5;
11
+ var DEFAULT_PROMPT_POLL_REQUEST_TIMEOUT_MS = 15e3;
12
+ var DEFAULT_PROMPT_RECOVERY_INACTIVITY_TIMEOUT_MS = 12e4;
10
13
  var AllowedChatIdSchema = z.union([z.number().int(), z.string().regex(/^-?\d+$/u).transform((value) => Number(value))]);
11
14
  var TelegramConfigSchema = z.preprocess((value) => value ?? {}, z.object({
12
15
  botToken: z.string().trim().min(1),
@@ -14,9 +17,15 @@ var TelegramConfigSchema = z.preprocess((value) => value ?? {}, z.object({
14
17
  apiRoot: z.string().trim().url().default(DEFAULT_TELEGRAM_API_ROOT)
15
18
  }));
16
19
  var StateConfigSchema = z.preprocess((value) => value ?? {}, z.object({ path: z.string().trim().min(1).default(DEFAULT_STATE_FILE_PATH) }));
20
+ var PromptConfigSchema = z.preprocess((value) => value ?? {}, z.object({
21
+ waitTimeoutMs: z.number().int().positive().default(DEFAULT_PROMPT_WAIT_TIMEOUT_MS),
22
+ pollRequestTimeoutMs: z.number().int().positive().default(DEFAULT_PROMPT_POLL_REQUEST_TIMEOUT_MS),
23
+ recoveryInactivityTimeoutMs: z.number().int().positive().default(DEFAULT_PROMPT_RECOVERY_INACTIVITY_TIMEOUT_MS)
24
+ }));
17
25
  var AppConfigSchema = z.object({
18
26
  telegram: TelegramConfigSchema,
19
27
  state: StateConfigSchema,
28
+ prompt: PromptConfigSchema,
20
29
  logLevel: z.string().default("info")
21
30
  });
22
31
  function loadAppConfig(configSource = {}, options = {}) {
@@ -28,6 +37,9 @@ function buildAppConfig(data, options) {
28
37
  telegramAllowedChatIds: data.telegram.allowedChatIds,
29
38
  telegramApiRoot: normalizeApiRoot(data.telegram.apiRoot),
30
39
  logLevel: data.logLevel,
40
+ promptWaitTimeoutMs: data.prompt.waitTimeoutMs,
41
+ promptPollRequestTimeoutMs: data.prompt.pollRequestTimeoutMs,
42
+ promptRecoveryInactivityTimeoutMs: data.prompt.recoveryInactivityTimeoutMs,
31
43
  stateFilePath: resolveStatePath(data, options.cwd ?? process.cwd())
32
44
  };
33
45
  }
@@ -102,6 +114,7 @@ function mergePluginConfigSources(...sources) {
102
114
  const normalized = source;
103
115
  const previousTelegram = merged.telegram;
104
116
  const previousState = merged.state;
117
+ const previousPrompt = merged.prompt;
105
118
  Object.assign(merged, normalized);
106
119
  if (normalized.telegram) merged.telegram = {
107
120
  ...previousTelegram ?? {},
@@ -111,6 +124,10 @@ function mergePluginConfigSources(...sources) {
111
124
  ...previousState ?? {},
112
125
  ...normalized.state
113
126
  };
127
+ if (normalized.prompt) merged.prompt = {
128
+ ...previousPrompt ?? {},
129
+ ...normalized.prompt
130
+ };
114
131
  }
115
132
  return merged;
116
133
  }
@@ -138,11 +155,13 @@ function orderPluginConfig(config) {
138
155
  const prioritizedKeys = new Set([
139
156
  "telegram",
140
157
  "state",
158
+ "prompt",
141
159
  "logLevel"
142
160
  ]);
143
161
  const ordered = {};
144
162
  if (config.telegram) ordered.telegram = config.telegram;
145
163
  if (config.state) ordered.state = config.state;
164
+ if (config.prompt) ordered.prompt = config.prompt;
146
165
  if (config.logLevel !== void 0) ordered.logLevel = config.logLevel;
147
166
  for (const [key, value] of Object.entries(config)) if (!prioritizedKeys.has(key)) ordered[key] = value;
148
167
  return ordered;
@@ -172,4 +191,4 @@ function stripLegacyVoiceConfig(config) {
172
191
  //#endregion
173
192
  export { writePluginConfigFile as a, loadAppConfig as c, preparePluginConfiguration as i, getOpenCodeConfigFilePath as n, OPENCODE_TBOT_VERSION as o, mergePluginConfigSources as r, DEFAULT_TELEGRAM_API_ROOT as s, getGlobalPluginConfigFilePath as t };
174
193
 
175
- //# sourceMappingURL=plugin-config-CCeFjxSf.js.map
194
+ //# sourceMappingURL=plugin-config-DNeV2Ckw.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-config-DNeV2Ckw.js","names":[],"sources":["../../src/app/config.ts","../../src/app/package-info.ts","../../src/app/plugin-config.ts"],"sourcesContent":["import { resolve } from \"node:path\";\nimport { z } from \"zod\";\n\nexport const DEFAULT_STATE_FILE_PATH = \"./data/opencode-tbot.state.json\";\nexport const DEFAULT_TELEGRAM_API_ROOT = \"https://api.telegram.org\";\nexport const DEFAULT_PROMPT_WAIT_TIMEOUT_MS = 1_800_000;\nexport const DEFAULT_PROMPT_POLL_REQUEST_TIMEOUT_MS = 15_000;\nexport const DEFAULT_PROMPT_RECOVERY_INACTIVITY_TIMEOUT_MS = 120_000;\n\nconst AllowedChatIdSchema = z.union([\n z.number().int(),\n z.string().regex(/^-?\\d+$/u).transform((value) => Number(value)),\n]);\n\nconst TelegramConfigSchema = z.preprocess(\n (value) => value ?? {},\n z.object({\n botToken: z.string().trim().min(1),\n allowedChatIds: z.array(AllowedChatIdSchema).default([]),\n apiRoot: z.string().trim().url().default(DEFAULT_TELEGRAM_API_ROOT),\n }),\n);\n\nconst StateConfigSchema = z.preprocess(\n (value) => value ?? {},\n z.object({\n path: z.string().trim().min(1).default(DEFAULT_STATE_FILE_PATH),\n }),\n);\n\nconst PromptConfigSchema = z.preprocess(\n (value) => value ?? {},\n z.object({\n waitTimeoutMs: z.number().int().positive().default(DEFAULT_PROMPT_WAIT_TIMEOUT_MS),\n pollRequestTimeoutMs: z.number().int().positive().default(DEFAULT_PROMPT_POLL_REQUEST_TIMEOUT_MS),\n recoveryInactivityTimeoutMs: z.number().int().positive().default(DEFAULT_PROMPT_RECOVERY_INACTIVITY_TIMEOUT_MS),\n }),\n);\n\nconst AppConfigSchema = z.object({\n telegram: TelegramConfigSchema,\n state: StateConfigSchema,\n prompt: PromptConfigSchema,\n logLevel: z.string().default(\"info\"),\n});\n\nexport interface PluginConfigSource {\n telegram?: {\n botToken?: string;\n allowedChatIds?: Array<number | string>;\n apiRoot?: string;\n [key: string]: unknown;\n };\n state?: {\n path?: string;\n [key: string]: unknown;\n };\n prompt?: {\n waitTimeoutMs?: number;\n pollRequestTimeoutMs?: number;\n recoveryInactivityTimeoutMs?: number;\n [key: string]: unknown;\n };\n logLevel?: string;\n [key: string]: unknown;\n}\n\nexport interface AppConfig {\n telegramBotToken: string;\n telegramAllowedChatIds: number[];\n telegramApiRoot: string;\n logLevel: string;\n promptWaitTimeoutMs: number;\n promptPollRequestTimeoutMs: number;\n promptRecoveryInactivityTimeoutMs: number;\n stateFilePath: string;\n}\n\nexport interface LoadAppConfigOptions {\n cwd?: string;\n}\n\nexport function loadAppConfig(\n configSource: PluginConfigSource | undefined = {},\n options: LoadAppConfigOptions = {},\n): AppConfig {\n const parsed = parseConfig(AppConfigSchema, configSource);\n\n return buildAppConfig(parsed, options);\n}\n\nexport const loadPluginConfig = loadAppConfig;\n\nfunction buildAppConfig(\n data: z.infer<typeof AppConfigSchema>,\n options: LoadAppConfigOptions,\n): AppConfig {\n return {\n telegramBotToken: data.telegram.botToken,\n telegramAllowedChatIds: data.telegram.allowedChatIds,\n telegramApiRoot: normalizeApiRoot(data.telegram.apiRoot),\n logLevel: data.logLevel,\n promptWaitTimeoutMs: data.prompt.waitTimeoutMs,\n promptPollRequestTimeoutMs: data.prompt.pollRequestTimeoutMs,\n promptRecoveryInactivityTimeoutMs: data.prompt.recoveryInactivityTimeoutMs,\n stateFilePath: resolveStatePath(data, options.cwd ?? process.cwd()),\n };\n}\n\nfunction resolveStatePath(\n data: z.infer<typeof AppConfigSchema>,\n cwd: string,\n): string {\n return resolve(cwd, data.state.path || DEFAULT_STATE_FILE_PATH);\n}\n\nfunction normalizeApiRoot(value: string): string {\n const normalized = value.trim();\n\n return normalized.endsWith(\"/\")\n ? normalized.slice(0, -1)\n : normalized;\n}\n\nfunction parseConfig<TSchema extends z.ZodTypeAny>(\n schema: TSchema,\n configSource: PluginConfigSource | undefined,\n): z.infer<TSchema> {\n const parsed = schema.safeParse(configSource ?? {});\n\n if (parsed.success) {\n return parsed.data;\n }\n\n throw new Error(\n `Invalid plugin configuration: ${JSON.stringify(parsed.error.flatten())}`,\n );\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nexport const OPENCODE_TBOT_VERSION = resolvePackageVersion();\n\nfunction resolvePackageVersion(): string {\n let directory = dirname(fileURLToPath(import.meta.url));\n\n while (true) {\n const packageFilePath = join(directory, \"package.json\");\n\n if (existsSync(packageFilePath)) {\n try {\n const parsed = JSON.parse(readFileSync(packageFilePath, \"utf8\")) as {\n version?: unknown;\n };\n\n if (typeof parsed.version === \"string\" && parsed.version.trim().length > 0) {\n return parsed.version;\n }\n } catch {\n // Fall through and continue searching parent directories.\n }\n }\n\n const parentDirectory = dirname(directory);\n\n if (parentDirectory === directory) {\n break;\n }\n\n directory = parentDirectory;\n }\n\n return \"unknown\";\n}\n","import { access, mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport type { PluginConfigSource } from \"./config.js\";\n\nexport const PLUGIN_CONFIG_FILE_NAME = \"tbot.config.json\";\nexport const GLOBAL_PLUGIN_DIRECTORY_NAME = \"opencode-tbot\";\nexport const GLOBAL_PLUGIN_CONFIG_FILE_NAME = \"config.json\";\nexport const OPENCODE_CONFIG_FILE_NAME = \"opencode.json\";\n\nexport interface PreparedPluginConfiguration {\n cwd: string;\n config: PluginConfigSource;\n globalConfigFilePath: string;\n projectConfigFilePath: string;\n ignoredProjectConfigFilePath?: string;\n configFilePath: string;\n}\n\nexport interface PreparePluginConfigurationOptions {\n cwd: string;\n config?: PluginConfigSource;\n homeDir?: string;\n}\n\nexport async function preparePluginConfiguration(\n options: PreparePluginConfigurationOptions,\n): Promise<PreparedPluginConfiguration> {\n const homeDir = options.homeDir ?? homedir();\n const globalConfigFilePath = getGlobalPluginConfigFilePath(homeDir);\n const projectConfigFilePath = await resolveProjectPluginConfigFilePath(options.cwd);\n const [globalConfig, hasIgnoredProjectConfig] = await Promise.all([\n loadPluginConfigFile(globalConfigFilePath),\n pathExists(projectConfigFilePath),\n ]);\n const config = stripLegacyVoiceConfig(mergePluginConfigSources(globalConfig, options.config));\n const ignoredProjectConfigFilePath = hasIgnoredProjectConfig\n ? projectConfigFilePath\n : undefined;\n const configFilePath = globalConfigFilePath;\n\n return {\n cwd: options.cwd,\n config,\n globalConfigFilePath,\n projectConfigFilePath,\n ...(ignoredProjectConfigFilePath ? { ignoredProjectConfigFilePath } : {}),\n configFilePath,\n };\n}\n\nexport function getOpenCodeConfigDirectory(homeDir: string = homedir()): string {\n return join(homeDir, \".config\", \"opencode\");\n}\n\nexport function getOpenCodeConfigFilePath(homeDir: string = homedir()): string {\n return join(getOpenCodeConfigDirectory(homeDir), OPENCODE_CONFIG_FILE_NAME);\n}\n\nexport function getGlobalPluginConfigFilePath(homeDir: string = homedir()): string {\n return join(\n getOpenCodeConfigDirectory(homeDir),\n GLOBAL_PLUGIN_DIRECTORY_NAME,\n GLOBAL_PLUGIN_CONFIG_FILE_NAME,\n );\n}\n\nexport async function writePluginConfigFile(\n configFilePath: string,\n config: PluginConfigSource,\n): Promise<void> {\n await mkdir(dirname(configFilePath), { recursive: true });\n await writeFile(configFilePath, serializePluginConfig(config), \"utf8\");\n}\n\nexport function mergePluginConfigSources(\n ...sources: Array<PluginConfigSource | undefined>\n): PluginConfigSource {\n const merged: PluginConfigSource = {};\n\n for (const source of sources) {\n if (!source) {\n continue;\n }\n\n const normalized = source;\n const previousTelegram = merged.telegram;\n const previousState = merged.state;\n const previousPrompt = merged.prompt;\n\n Object.assign(merged, normalized);\n\n if (normalized.telegram) {\n merged.telegram = {\n ...(previousTelegram ?? {}),\n ...normalized.telegram,\n };\n }\n\n if (normalized.state) {\n merged.state = {\n ...(previousState ?? {}),\n ...normalized.state,\n };\n }\n\n if (normalized.prompt) {\n merged.prompt = {\n ...(previousPrompt ?? {}),\n ...normalized.prompt,\n };\n }\n }\n\n return merged;\n}\n\nexport function serializePluginConfig(config: PluginConfigSource): string {\n return `${JSON.stringify(orderPluginConfig(config), null, 2)}\\n`;\n}\n\nasync function loadPluginConfigFile(configFilePath: string): Promise<PluginConfigSource> {\n try {\n const content = await readFile(configFilePath, \"utf8\");\n\n return parsePluginConfigText(content, configFilePath);\n } catch (error) {\n if (isMissingFileError(error)) {\n return {};\n }\n\n throw error;\n }\n}\n\nfunction parsePluginConfigText(\n content: string,\n configFilePath: string,\n): PluginConfigSource {\n try {\n const parsed = JSON.parse(content) as unknown;\n\n if (!isPlainObject(parsed)) {\n throw new Error(\"Config root must be a JSON object.\");\n }\n\n return parsed as PluginConfigSource;\n } catch (error) {\n throw new Error(\n [\n `Failed to parse ${configFilePath} as JSON.`,\n error instanceof Error ? error.message : String(error),\n ].join(\" \"),\n );\n }\n}\n\nfunction orderPluginConfig(config: PluginConfigSource): PluginConfigSource {\n const prioritizedKeys = new Set([\n \"telegram\",\n \"state\",\n \"prompt\",\n \"logLevel\",\n ]);\n const ordered: PluginConfigSource = {};\n\n if (config.telegram) {\n ordered.telegram = config.telegram;\n }\n\n if (config.state) {\n ordered.state = config.state;\n }\n\n if (config.prompt) {\n ordered.prompt = config.prompt;\n }\n\n if (config.logLevel !== undefined) {\n ordered.logLevel = config.logLevel;\n }\n\n for (const [key, value] of Object.entries(config)) {\n if (!prioritizedKeys.has(key)) {\n ordered[key] = value;\n }\n }\n\n return ordered;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction isMissingFileError(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && \"code\" in error && error.code === \"ENOENT\";\n}\n\nasync function resolveProjectPluginConfigFilePath(cwd: string): Promise<string> {\n const preferredPath = join(cwd, PLUGIN_CONFIG_FILE_NAME);\n\n return preferredPath;\n}\n\nasync function pathExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath);\n return true;\n } catch (error) {\n if (isMissingFileError(error)) {\n return false;\n }\n\n throw error;\n }\n}\n\nfunction stripLegacyVoiceConfig(config: PluginConfigSource): PluginConfigSource {\n const { openrouter: _openrouter, ...rest } = config as PluginConfigSource & {\n openrouter?: unknown;\n };\n\n return rest;\n}\n"],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as writePluginConfigFile, n as getOpenCodeConfigFilePath, o as OPENCODE_TBOT_VERSION, r as mergePluginConfigSources, t as getGlobalPluginConfigFilePath } from "./assets/plugin-config-CCeFjxSf.js";
1
+ import { a as writePluginConfigFile, n as getOpenCodeConfigFilePath, o as OPENCODE_TBOT_VERSION, r as mergePluginConfigSources, t as getGlobalPluginConfigFilePath } from "./assets/plugin-config-DNeV2Ckw.js";
2
2
  import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
3
3
  import { homedir } from "node:os";
4
4
  import { dirname, join, resolve } from "node:path";
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import "./assets/plugin-config-CCeFjxSf.js";
1
+ import "./assets/plugin-config-DNeV2Ckw.js";
2
2
  import { TelegramBotPlugin, ensureTelegramBotPluginRuntime, resetTelegramBotPluginRuntimeForTests } from "./plugin.js";
3
3
  export { TelegramBotPlugin, TelegramBotPlugin as default, ensureTelegramBotPluginRuntime, resetTelegramBotPluginRuntimeForTests };