opencode-tbot 0.1.23 → 0.1.24
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 +4 -9
- package/README.md +4 -9
- package/README.zh-CN.md +4 -9
- package/dist/assets/{plugin-config-B8ginwol.js → plugin-config-CCeFjxSf.js} +6 -4
- package/dist/assets/plugin-config-CCeFjxSf.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/plugin.js +46 -27
- package/dist/plugin.js.map +1 -1
- package/package.json +1 -2
- package/dist/assets/plugin-config-B8ginwol.js.map +0 -1
- package/tbot.config.example.json +0 -11
package/README.ja.md
CHANGED
|
@@ -62,18 +62,13 @@ npm exec --package opencode-tbot@latest opencode-tbot -- update
|
|
|
62
62
|
|
|
63
63
|
## 設定
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
ランタイム設定は `~/.config/opencode/opencode-tbot/config.json` からのみ読み込まれます。
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
2. `<worktree>/tbot.config.json` のプロジェクト上書き設定
|
|
69
|
-
|
|
70
|
-
プロジェクト設定はグローバル設定に上書きマージされます。`telegram` と `state` はセクション単位でディープマージされます。
|
|
67
|
+
古い `<worktree>/tbot.config.json` はランタイムでは無視されます。検出された場合は、値をグローバル設定へ移行できるように警告ログを出します。
|
|
71
68
|
|
|
72
69
|
古い `openrouter` 音声転写設定はランタイムでは無視され、インストーラーが設定を書き直す際にも削除されます。
|
|
73
70
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
### `tbot.config.json` の例
|
|
71
|
+
### グローバル `config.json` の例
|
|
77
72
|
|
|
78
73
|
```json
|
|
79
74
|
{
|
|
@@ -109,7 +104,7 @@ npm exec --package opencode-tbot@latest opencode-tbot -- update
|
|
|
109
104
|
## クイックスタート
|
|
110
105
|
|
|
111
106
|
1. `npm exec --package opencode-tbot@latest opencode-tbot -- install` でプラグインをインストールします。
|
|
112
|
-
2. 特定の chat
|
|
107
|
+
2. 特定の chat のみ許可したい場合は、`~/.config/opencode/opencode-tbot/config.json` で `telegram.allowedChatIds` を設定します。
|
|
113
108
|
3. 対象の worktree で OpenCode を起動し、プラグインランタイムを読み込ませます。
|
|
114
109
|
4. Telegram で `/status` を実行し、接続を確認します。
|
|
115
110
|
5. `/new [title]` を実行するか、テキストメッセージを直接送信して使い始めます。
|
package/README.md
CHANGED
|
@@ -62,18 +62,13 @@ npm exec --package opencode-tbot@latest opencode-tbot -- update
|
|
|
62
62
|
|
|
63
63
|
## Configuration
|
|
64
64
|
|
|
65
|
-
Runtime config is loaded
|
|
65
|
+
Runtime config is loaded from `~/.config/opencode/opencode-tbot/config.json`.
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
2. Project overrides from `<worktree>/tbot.config.json`
|
|
69
|
-
|
|
70
|
-
Project config is merged on top of the global config. `telegram` and `state` are deep-merged by section.
|
|
67
|
+
Legacy `<worktree>/tbot.config.json` files are ignored at runtime. If one is present, the plugin logs a warning so you can migrate its values into the global config.
|
|
71
68
|
|
|
72
69
|
Legacy `openrouter` voice-transcription settings are ignored at runtime. When the installer rewrites the config, it removes them.
|
|
73
70
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
### Example `tbot.config.json`
|
|
71
|
+
### Example Global `config.json`
|
|
77
72
|
|
|
78
73
|
```json
|
|
79
74
|
{
|
|
@@ -109,7 +104,7 @@ The repository also includes [tbot.config.example.json](./tbot.config.example.js
|
|
|
109
104
|
## Quick Start
|
|
110
105
|
|
|
111
106
|
1. Install the plugin with `npm exec --package opencode-tbot@latest opencode-tbot -- install`.
|
|
112
|
-
2. Set `telegram.allowedChatIds` in
|
|
107
|
+
2. Set `telegram.allowedChatIds` in `~/.config/opencode/opencode-tbot/config.json` if you want to restrict the bot to specific chats.
|
|
113
108
|
3. Start OpenCode in the target worktree so the plugin runtime can load.
|
|
114
109
|
4. In Telegram, run `/status` to verify the connection.
|
|
115
110
|
5. Run `/new [title]` or send a text message directly to start working.
|
package/README.zh-CN.md
CHANGED
|
@@ -62,18 +62,13 @@ npm exec --package opencode-tbot@latest opencode-tbot -- update
|
|
|
62
62
|
|
|
63
63
|
## 配置
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
运行时配置只会从 `~/.config/opencode/opencode-tbot/config.json` 加载。
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
2. 项目覆盖配置 `<worktree>/tbot.config.json`
|
|
69
|
-
|
|
70
|
-
项目配置会覆盖全局默认值;`telegram` 和 `state` 会按分段进行深合并。
|
|
67
|
+
遗留的 `<worktree>/tbot.config.json` 会在运行时被忽略;如果检测到该文件,插件会记录一条警告,提示你把其中的值迁移到全局配置。
|
|
71
68
|
|
|
72
69
|
遗留的 `openrouter` 语音转写配置在运行时会被忽略;安装器重写配置时也会自动移除这些字段。
|
|
73
70
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
### `tbot.config.json` 示例
|
|
71
|
+
### 全局 `config.json` 示例
|
|
77
72
|
|
|
78
73
|
```json
|
|
79
74
|
{
|
|
@@ -109,7 +104,7 @@ npm exec --package opencode-tbot@latest opencode-tbot -- update
|
|
|
109
104
|
## 快速开始
|
|
110
105
|
|
|
111
106
|
1. 使用 `npm exec --package opencode-tbot@latest opencode-tbot -- install` 安装插件。
|
|
112
|
-
2. 如果你只想允许特定聊天使用 bot,请在
|
|
107
|
+
2. 如果你只想允许特定聊天使用 bot,请在 `~/.config/opencode/opencode-tbot/config.json` 中设置 `telegram.allowedChatIds`。
|
|
113
108
|
3. 在目标 worktree 中启动 OpenCode,让插件运行时被加载。
|
|
114
109
|
4. 在 Telegram 中执行 `/status` 验证连接是否正常。
|
|
115
110
|
5. 执行 `/new [title]`,或者直接发送文本消息开始使用。
|
|
@@ -69,14 +69,16 @@ var OPENCODE_CONFIG_FILE_NAME = "opencode.json";
|
|
|
69
69
|
async function preparePluginConfiguration(options) {
|
|
70
70
|
const globalConfigFilePath = getGlobalPluginConfigFilePath(options.homeDir ?? homedir());
|
|
71
71
|
const projectConfigFilePath = await resolveProjectPluginConfigFilePath(options.cwd);
|
|
72
|
-
const [globalConfig,
|
|
73
|
-
const config = stripLegacyVoiceConfig(mergePluginConfigSources(globalConfig,
|
|
74
|
-
const
|
|
72
|
+
const [globalConfig, hasIgnoredProjectConfig] = await Promise.all([loadPluginConfigFile(globalConfigFilePath), pathExists(projectConfigFilePath)]);
|
|
73
|
+
const config = stripLegacyVoiceConfig(mergePluginConfigSources(globalConfig, options.config));
|
|
74
|
+
const ignoredProjectConfigFilePath = hasIgnoredProjectConfig ? projectConfigFilePath : void 0;
|
|
75
|
+
const configFilePath = globalConfigFilePath;
|
|
75
76
|
return {
|
|
76
77
|
cwd: options.cwd,
|
|
77
78
|
config,
|
|
78
79
|
globalConfigFilePath,
|
|
79
80
|
projectConfigFilePath,
|
|
81
|
+
...ignoredProjectConfigFilePath ? { ignoredProjectConfigFilePath } : {},
|
|
80
82
|
configFilePath
|
|
81
83
|
};
|
|
82
84
|
}
|
|
@@ -170,4 +172,4 @@ function stripLegacyVoiceConfig(config) {
|
|
|
170
172
|
//#endregion
|
|
171
173
|
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 };
|
|
172
174
|
|
|
173
|
-
//# sourceMappingURL=plugin-config-
|
|
175
|
+
//# sourceMappingURL=plugin-config-CCeFjxSf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-config-CCeFjxSf.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\";\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 AppConfigSchema = z.object({\n telegram: TelegramConfigSchema,\n state: StateConfigSchema,\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 logLevel?: string;\n [key: string]: unknown;\n}\n\nexport interface AppConfig {\n telegramBotToken: string;\n telegramAllowedChatIds: number[];\n telegramApiRoot: string;\n logLevel: string;\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 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\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\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 \"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.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-
|
|
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";
|
|
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-
|
|
1
|
+
import "./assets/plugin-config-CCeFjxSf.js";
|
|
2
2
|
import { TelegramBotPlugin, ensureTelegramBotPluginRuntime, resetTelegramBotPluginRuntimeForTests } from "./plugin.js";
|
|
3
3
|
export { TelegramBotPlugin, TelegramBotPlugin as default, ensureTelegramBotPluginRuntime, resetTelegramBotPluginRuntimeForTests };
|
package/dist/plugin.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as loadAppConfig, i as preparePluginConfiguration, o as OPENCODE_TBOT_VERSION } from "./assets/plugin-config-
|
|
1
|
+
import { c as loadAppConfig, i as preparePluginConfiguration, o as OPENCODE_TBOT_VERSION } from "./assets/plugin-config-CCeFjxSf.js";
|
|
2
2
|
import { mkdir, readFile, rename, stat, writeFile } from "node:fs/promises";
|
|
3
3
|
import { dirname, isAbsolute, join } from "node:path";
|
|
4
4
|
import { parse, printParseErrorCode } from "jsonc-parser";
|
|
@@ -398,16 +398,16 @@ var OpenCodeClient = class {
|
|
|
398
398
|
}
|
|
399
399
|
async resolvePromptResponse(input, data, knownMessageIds, startedAt) {
|
|
400
400
|
const structured = input.structured ?? false;
|
|
401
|
-
if (!shouldPollPromptMessage(data, structured)) return data;
|
|
402
|
-
const messageId = extractMessageId(data.info);
|
|
401
|
+
if (data && !shouldPollPromptMessage(data, structured)) return data;
|
|
402
|
+
const messageId = data ? extractMessageId(data.info) : null;
|
|
403
403
|
const candidateOptions = {
|
|
404
404
|
initialMessageId: messageId,
|
|
405
|
-
initialParentId: toAssistantMessage(data.info)?.parentID ?? null,
|
|
405
|
+
initialParentId: data ? toAssistantMessage(data.info)?.parentID ?? null : null,
|
|
406
406
|
knownMessageIds,
|
|
407
407
|
requestStartedAt: resolvePromptCandidateStartTime(startedAt, data),
|
|
408
408
|
structured
|
|
409
409
|
};
|
|
410
|
-
let bestCandidate = selectPromptResponseCandidate([data], candidateOptions)
|
|
410
|
+
let bestCandidate = selectPromptResponseCandidate(data ? [data] : [], candidateOptions);
|
|
411
411
|
const deadlineAt = Date.now() + this.promptRequestTimeouts.totalPollMs;
|
|
412
412
|
let idleStatusSeen = false;
|
|
413
413
|
let attempt = 0;
|
|
@@ -422,14 +422,16 @@ var OpenCodeClient = class {
|
|
|
422
422
|
if (messageId) {
|
|
423
423
|
const next = await this.fetchPromptMessage(input.sessionId, messageId);
|
|
424
424
|
if (next) {
|
|
425
|
-
|
|
426
|
-
if (
|
|
425
|
+
const nextCandidate = selectPromptResponseCandidate([bestCandidate, next], candidateOptions);
|
|
426
|
+
if (nextCandidate) bestCandidate = nextCandidate;
|
|
427
|
+
if (bestCandidate && !shouldPollPromptMessage(bestCandidate, structured)) return bestCandidate;
|
|
427
428
|
}
|
|
428
429
|
}
|
|
429
430
|
const latest = await this.findLatestPromptResponse(input.sessionId, candidateOptions, "poll-messages");
|
|
430
431
|
if (latest) {
|
|
431
|
-
|
|
432
|
-
if (
|
|
432
|
+
const nextCandidate = selectPromptResponseCandidate([bestCandidate, latest], candidateOptions);
|
|
433
|
+
if (nextCandidate) bestCandidate = nextCandidate;
|
|
434
|
+
if (bestCandidate && !shouldPollPromptMessage(bestCandidate, structured)) return bestCandidate;
|
|
433
435
|
}
|
|
434
436
|
if ((await this.fetchPromptSessionStatus(input.sessionId))?.type === "idle") {
|
|
435
437
|
if (idleStatusSeen) break;
|
|
@@ -438,8 +440,8 @@ var OpenCodeClient = class {
|
|
|
438
440
|
if (Date.now() >= deadlineAt) break;
|
|
439
441
|
}
|
|
440
442
|
const latest = await this.findLatestPromptResponse(input.sessionId, candidateOptions, "final-scan");
|
|
441
|
-
const resolved = selectPromptResponseCandidate([bestCandidate, latest], candidateOptions)
|
|
442
|
-
if (shouldPollPromptMessage(resolved, structured)) {
|
|
443
|
+
const resolved = selectPromptResponseCandidate([bestCandidate, latest], candidateOptions);
|
|
444
|
+
if (!resolved || shouldPollPromptMessage(resolved, structured)) {
|
|
443
445
|
const error = createOpenCodePromptTimeoutError({
|
|
444
446
|
sessionId: input.sessionId,
|
|
445
447
|
stage: "final-scan",
|
|
@@ -568,7 +570,31 @@ var OpenCodeClient = class {
|
|
|
568
570
|
return unwrapSdkData(await this.client.config.providers(void 0, SDK_OPTIONS));
|
|
569
571
|
}
|
|
570
572
|
async sendPromptRequest(input, parts) {
|
|
573
|
+
const requestBody = {
|
|
574
|
+
...input.agent ? { agent: input.agent } : {},
|
|
575
|
+
...input.structured ? { format: STRUCTURED_REPLY_SCHEMA } : {},
|
|
576
|
+
...input.model ? { model: input.model } : {},
|
|
577
|
+
...input.variant ? { variant: input.variant } : {},
|
|
578
|
+
parts
|
|
579
|
+
};
|
|
580
|
+
const requestParameters = {
|
|
581
|
+
sessionID: input.sessionId,
|
|
582
|
+
...requestBody
|
|
583
|
+
};
|
|
571
584
|
try {
|
|
585
|
+
if (typeof this.client.session?.promptAsync === "function") {
|
|
586
|
+
await this.runPromptRequestWithTimeout({
|
|
587
|
+
sessionId: input.sessionId,
|
|
588
|
+
stage: "send-prompt",
|
|
589
|
+
timeoutMs: this.promptRequestTimeouts.sendMs
|
|
590
|
+
}, async (signal) => {
|
|
591
|
+
await this.client.session.promptAsync(requestParameters, {
|
|
592
|
+
...SDK_OPTIONS,
|
|
593
|
+
signal
|
|
594
|
+
});
|
|
595
|
+
});
|
|
596
|
+
return null;
|
|
597
|
+
}
|
|
572
598
|
return await this.runPromptRequestWithTimeout({
|
|
573
599
|
sessionId: input.sessionId,
|
|
574
600
|
stage: "send-prompt",
|
|
@@ -577,23 +603,10 @@ var OpenCodeClient = class {
|
|
|
577
603
|
if (hasRawSdkMethod(this.client, "post")) return normalizePromptResponse(await this.requestRaw("post", {
|
|
578
604
|
url: "/session/{sessionID}/message",
|
|
579
605
|
path: { sessionID: input.sessionId },
|
|
580
|
-
body:
|
|
581
|
-
...input.agent ? { agent: input.agent } : {},
|
|
582
|
-
...input.structured ? { format: STRUCTURED_REPLY_SCHEMA } : {},
|
|
583
|
-
...input.model ? { model: input.model } : {},
|
|
584
|
-
...input.variant ? { variant: input.variant } : {},
|
|
585
|
-
parts
|
|
586
|
-
},
|
|
606
|
+
body: requestBody,
|
|
587
607
|
signal
|
|
588
608
|
}));
|
|
589
|
-
return normalizePromptResponse(unwrapSdkData(await this.client.session.prompt({
|
|
590
|
-
sessionID: input.sessionId,
|
|
591
|
-
...input.agent ? { agent: input.agent } : {},
|
|
592
|
-
...input.structured ? { format: STRUCTURED_REPLY_SCHEMA } : {},
|
|
593
|
-
...input.model ? { model: input.model } : {},
|
|
594
|
-
...input.variant ? { variant: input.variant } : {},
|
|
595
|
-
parts
|
|
596
|
-
}, {
|
|
609
|
+
return normalizePromptResponse(unwrapSdkData(await this.client.session.prompt(requestParameters, {
|
|
597
610
|
...SDK_OPTIONS,
|
|
598
611
|
signal
|
|
599
612
|
})));
|
|
@@ -952,6 +965,7 @@ function getPromptResponseCandidateRank(message, options) {
|
|
|
952
965
|
};
|
|
953
966
|
}
|
|
954
967
|
function resolvePromptCandidateStartTime(startedAt, initialMessage) {
|
|
968
|
+
if (!initialMessage) return null;
|
|
955
969
|
const initialCreatedAt = coerceFiniteNumber(toAssistantMessage(initialMessage.info)?.time?.created);
|
|
956
970
|
if (initialCreatedAt === null) return startedAt;
|
|
957
971
|
return areComparablePromptTimestamps(startedAt, initialCreatedAt) ? startedAt : initialCreatedAt;
|
|
@@ -4679,6 +4693,11 @@ async function startPluginRuntime(options, cwd) {
|
|
|
4679
4693
|
});
|
|
4680
4694
|
const { config, container } = bootstrapApp(options.context.client, preparedConfiguration.config, { cwd: preparedConfiguration.cwd });
|
|
4681
4695
|
try {
|
|
4696
|
+
if (preparedConfiguration.ignoredProjectConfigFilePath) container.logger.warn({
|
|
4697
|
+
cwd: preparedConfiguration.cwd,
|
|
4698
|
+
ignoredProjectConfigFilePath: preparedConfiguration.ignoredProjectConfigFilePath,
|
|
4699
|
+
globalConfigFilePath: preparedConfiguration.globalConfigFilePath
|
|
4700
|
+
}, "legacy worktree plugin config is ignored; migrate settings to the global opencode-tbot config");
|
|
4682
4701
|
const runtime = await startRuntime({
|
|
4683
4702
|
config,
|
|
4684
4703
|
container
|
|
@@ -4686,7 +4705,7 @@ async function startPluginRuntime(options, cwd) {
|
|
|
4686
4705
|
container.logger.info({
|
|
4687
4706
|
cwd: preparedConfiguration.cwd,
|
|
4688
4707
|
globalConfigFilePath: preparedConfiguration.globalConfigFilePath,
|
|
4689
|
-
|
|
4708
|
+
ignoredProjectConfigFilePath: preparedConfiguration.ignoredProjectConfigFilePath,
|
|
4690
4709
|
configFilePath: preparedConfiguration.configFilePath,
|
|
4691
4710
|
mode: "plugin"
|
|
4692
4711
|
}, "telegram bot plugin runtime started");
|