opencode-tbot 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -72
- package/README.zh-CN.md +25 -73
- package/dist/assets/{plugin-config-Crgl_PZz.js → plugin-config-BYsYAzvx.js} +6 -45
- package/dist/assets/plugin-config-BYsYAzvx.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/plugin.js +276 -152
- package/dist/plugin.js.map +1 -1
- package/package.json +2 -3
- package/INSTALL.md +0 -92
- package/dist/assets/plugin-config-Crgl_PZz.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-tbot",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Telegram bot plugin for OpenCode",
|
|
6
6
|
"license": "MIT",
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
"dist",
|
|
14
14
|
"README.md",
|
|
15
15
|
"README.zh-CN.md",
|
|
16
|
-
"INSTALL.md",
|
|
17
16
|
"tbot.config.example.json",
|
|
18
17
|
"LICENSE"
|
|
19
18
|
],
|
|
@@ -61,4 +60,4 @@
|
|
|
61
60
|
"typescript": "^5.6.2",
|
|
62
61
|
"vite": "^8.0.1"
|
|
63
62
|
}
|
|
64
|
-
}
|
|
63
|
+
}
|
package/INSTALL.md
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
# Install `opencode-tbot`
|
|
2
|
-
|
|
3
|
-
## Recommended
|
|
4
|
-
|
|
5
|
-
Run:
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npx opencode-tbot@latest install
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
The installer will:
|
|
12
|
-
|
|
13
|
-
1. update `~/.config/opencode/opencode.json`
|
|
14
|
-
2. ensure the `plugin` array contains `opencode-tbot@latest`
|
|
15
|
-
3. prompt for the Telegram bot token
|
|
16
|
-
4. ask whether voice transcription should be enabled
|
|
17
|
-
5. prompt for the OpenRouter API key when voice transcription is enabled
|
|
18
|
-
6. write plugin defaults to `~/.config/opencode/opencode-tbot/config.json`
|
|
19
|
-
|
|
20
|
-
Restart OpenCode after installation.
|
|
21
|
-
|
|
22
|
-
## Non-Interactive
|
|
23
|
-
|
|
24
|
-
Example:
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
npx opencode-tbot@latest install \
|
|
28
|
-
--bot-token <telegram-token> \
|
|
29
|
-
--disable-voice
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
If voice transcription is enabled:
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
npx opencode-tbot@latest install \
|
|
36
|
-
--bot-token <telegram-token> \
|
|
37
|
-
--enable-voice \
|
|
38
|
-
--openrouter-api-key <openrouter-key>
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Useful flags:
|
|
42
|
-
|
|
43
|
-
- `--telegram-api-root <url>`
|
|
44
|
-
- `--skip-register`
|
|
45
|
-
- `--home-dir <path>`
|
|
46
|
-
|
|
47
|
-
`--skip-register` only skips the OpenCode global registration step. The plugin config file is still written.
|
|
48
|
-
|
|
49
|
-
## Project Overrides
|
|
50
|
-
|
|
51
|
-
The installer writes global defaults to:
|
|
52
|
-
|
|
53
|
-
- `~/.config/opencode/opencode-tbot/config.json`
|
|
54
|
-
|
|
55
|
-
You can override them per worktree with:
|
|
56
|
-
|
|
57
|
-
- `<worktree>/tbot.config.json`
|
|
58
|
-
- legacy fallback: `<worktree>/opencode-tbot.config.json`
|
|
59
|
-
|
|
60
|
-
The runtime loads global defaults first, then deep-merges the project config on top.
|
|
61
|
-
|
|
62
|
-
Example project override:
|
|
63
|
-
|
|
64
|
-
```json
|
|
65
|
-
{
|
|
66
|
-
"telegram": {
|
|
67
|
-
"allowedChatIds": [123456789]
|
|
68
|
-
},
|
|
69
|
-
"state": {
|
|
70
|
-
"path": "./data/opencode-tbot.state.json"
|
|
71
|
-
},
|
|
72
|
-
"logLevel": "info"
|
|
73
|
-
}
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
## Agent Prompt
|
|
77
|
-
|
|
78
|
-
If you want another coding agent to perform the install, give it this:
|
|
79
|
-
|
|
80
|
-
```text
|
|
81
|
-
Install opencode-tbot for OpenCode by running:
|
|
82
|
-
npx opencode-tbot@latest install
|
|
83
|
-
|
|
84
|
-
If the environment is non-interactive, use:
|
|
85
|
-
- --bot-token for the Telegram bot token
|
|
86
|
-
- --enable-voice or --disable-voice
|
|
87
|
-
- --openrouter-api-key when voice transcription is enabled
|
|
88
|
-
|
|
89
|
-
Do not remove unrelated existing configuration.
|
|
90
|
-
Preserve existing plugins in ~/.config/opencode/opencode.json.
|
|
91
|
-
Show me the final changes and tell me to restart OpenCode.
|
|
92
|
-
```
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-config-Crgl_PZz.js","names":[],"sources":["../../src/app/config.ts","../../src/app/plugin-config.ts"],"sourcesContent":["import { resolve } from \"node:path\";\nimport { z } from \"zod\";\n\nexport const DEFAULT_OPENROUTER_MODEL = \"openai/gpt-audio-mini\";\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 LegacyDatabaseConfigSchema = z.preprocess(\n (value) => value ?? {},\n z.object({\n path: z.string().trim().min(1).optional(),\n }),\n);\n\nconst OpenRouterConfigSchema = z.preprocess(\n (value) => value ?? {},\n z.object({\n apiKey: z.string().default(\"\"),\n model: z.string().default(DEFAULT_OPENROUTER_MODEL),\n timeoutMs: z.coerce.number().int().positive().default(30_000),\n transcriptionPrompt: z.string().default(\"\"),\n }),\n);\n\nconst AppConfigSchema = z.preprocess(\n normalizeLegacyConfigSource,\n z.object({\n telegram: TelegramConfigSchema,\n state: StateConfigSchema,\n database: LegacyDatabaseConfigSchema.optional(),\n openrouter: OpenRouterConfigSchema,\n logLevel: z.string().default(\"info\"),\n }),\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 database?: {\n path?: string;\n [key: string]: unknown;\n };\n openrouter?: {\n apiKey?: string;\n model?: string;\n timeoutMs?: number;\n transcriptionPrompt?: string;\n [key: string]: unknown;\n };\n logLevel?: string;\n [key: string]: unknown;\n}\n\nexport interface AppOpenRouterConfig {\n configured: boolean;\n apiKey: string | null;\n model: string;\n timeoutMs: number;\n transcriptionPrompt: string | null;\n}\n\nexport interface AppConfig {\n telegramBotToken: string;\n telegramAllowedChatIds: number[];\n telegramApiRoot: string;\n logLevel: string;\n stateFilePath: string;\n openrouter: AppOpenRouterConfig;\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 const openRouterApiKey = normalizeOptionalString(data.openrouter.apiKey);\n const openRouterModel = normalizeOptionalString(data.openrouter.model) ?? DEFAULT_OPENROUTER_MODEL;\n const transcriptionPrompt = normalizeOptionalString(data.openrouter.transcriptionPrompt);\n\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 openrouter: {\n configured: !!openRouterApiKey,\n apiKey: openRouterApiKey,\n model: openRouterModel,\n timeoutMs: data.openrouter.timeoutMs,\n transcriptionPrompt,\n },\n };\n}\n\nfunction normalizeOptionalString(value: string): string | null {\n const normalized = value.trim();\n\n return normalized.length > 0 ? normalized : null;\n}\n\nfunction resolveStatePath(\n data: z.infer<typeof AppConfigSchema>,\n cwd: string,\n): string {\n return resolve(cwd, data.state.path || data.database?.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 normalizeLegacyConfigSource(value: unknown): unknown {\n if (!isPlainObject(value)) {\n return value ?? {};\n }\n\n const source = value as PluginConfigSource;\n\n if (source.state?.path || !source.database?.path) {\n return source;\n }\n\n return {\n ...source,\n state: {\n ...(source.state ?? {}),\n path: source.database.path,\n },\n };\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\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\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 LEGACY_PLUGIN_CONFIG_FILE_NAME = \"opencode-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 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, projectConfig] = await Promise.all([\n loadPluginConfigFile(globalConfigFilePath),\n loadPluginConfigFile(projectConfigFilePath),\n ]);\n const config = mergePluginConfigSources(globalConfig, projectConfig, options.config);\n const configFilePath = await pathExists(projectConfigFilePath)\n ? projectConfigFilePath\n : globalConfigFilePath;\n\n return {\n cwd: options.cwd,\n config,\n globalConfigFilePath,\n projectConfigFilePath,\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 = normalizePluginConfigSource(source);\n const previousTelegram = merged.telegram;\n const previousState = merged.state;\n const previousDatabase = merged.database;\n const previousOpenRouter = merged.openrouter;\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.database) {\n merged.database = {\n ...(previousDatabase ?? {}),\n ...normalized.database,\n };\n }\n\n if (normalized.openrouter) {\n merged.openrouter = {\n ...(previousOpenRouter ?? {}),\n ...normalized.openrouter,\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 \"database\",\n \"openrouter\",\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.database) {\n ordered.database = config.database;\n }\n\n if (config.openrouter) {\n ordered.openrouter = config.openrouter;\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 if (await pathExists(preferredPath)) {\n return preferredPath;\n }\n\n const legacyPath = join(cwd, LEGACY_PLUGIN_CONFIG_FILE_NAME);\n\n if (await pathExists(legacyPath)) {\n return legacyPath;\n }\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 normalizePluginConfigSource(source: PluginConfigSource): PluginConfigSource {\n if (source.state?.path || !source.database?.path) {\n return source;\n }\n\n return {\n ...source,\n state: {\n ...(source.state ?? {}),\n path: source.database.path,\n },\n };\n}\n"],"mappings":"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"}
|