opencode-gateway 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/dist/cli.js +0 -0
  2. package/dist/index.js +20907 -52
  3. package/dist/telegram/client.d.ts +1 -1
  4. package/dist/telegram/poller.d.ts +16 -1
  5. package/dist/telegram/runtime.d.ts +3 -1
  6. package/dist/telegram/state.d.ts +7 -0
  7. package/package.json +1 -1
  8. package/dist/binding/execution.js +0 -1
  9. package/dist/binding/gateway.js +0 -1
  10. package/dist/binding/index.js +0 -4
  11. package/dist/binding/opencode.js +0 -1
  12. package/dist/cli/args.js +0 -53
  13. package/dist/cli/doctor.js +0 -49
  14. package/dist/cli/init.js +0 -40
  15. package/dist/cli/opencode-config-file.js +0 -18
  16. package/dist/cli/opencode-config.js +0 -194
  17. package/dist/cli/paths.js +0 -22
  18. package/dist/cli/templates.js +0 -41
  19. package/dist/config/cron.js +0 -52
  20. package/dist/config/gateway.js +0 -148
  21. package/dist/config/memory.js +0 -105
  22. package/dist/config/paths.js +0 -39
  23. package/dist/config/telegram.js +0 -91
  24. package/dist/cron/runtime.js +0 -402
  25. package/dist/delivery/telegram.js +0 -75
  26. package/dist/delivery/text.js +0 -175
  27. package/dist/gateway.js +0 -117
  28. package/dist/host/file-sender.js +0 -59
  29. package/dist/host/logger.js +0 -53
  30. package/dist/host/transport.js +0 -35
  31. package/dist/mailbox/router.js +0 -16
  32. package/dist/media/mime.js +0 -45
  33. package/dist/memory/prompt.js +0 -122
  34. package/dist/opencode/adapter.js +0 -340
  35. package/dist/opencode/driver-hub.js +0 -82
  36. package/dist/opencode/event-normalize.js +0 -48
  37. package/dist/opencode/event-stream.js +0 -65
  38. package/dist/opencode/events.js +0 -1
  39. package/dist/questions/client.js +0 -36
  40. package/dist/questions/format.js +0 -36
  41. package/dist/questions/normalize.js +0 -45
  42. package/dist/questions/parser.js +0 -96
  43. package/dist/questions/runtime.js +0 -195
  44. package/dist/questions/types.js +0 -1
  45. package/dist/runtime/attachments.js +0 -12
  46. package/dist/runtime/conversation-coordinator.js +0 -22
  47. package/dist/runtime/executor.js +0 -407
  48. package/dist/runtime/mailbox.js +0 -112
  49. package/dist/runtime/opencode-runner.js +0 -79
  50. package/dist/runtime/runtime-singleton.js +0 -28
  51. package/dist/session/context.js +0 -23
  52. package/dist/session/conversation-key.js +0 -3
  53. package/dist/session/switcher.js +0 -59
  54. package/dist/session/system-prompt.js +0 -52
  55. package/dist/store/migrations.js +0 -197
  56. package/dist/store/sqlite.js +0 -777
  57. package/dist/telegram/client.js +0 -179
  58. package/dist/telegram/media.js +0 -65
  59. package/dist/telegram/normalize.js +0 -119
  60. package/dist/telegram/poller.js +0 -97
  61. package/dist/telegram/runtime.js +0 -133
  62. package/dist/telegram/state.js +0 -128
  63. package/dist/telegram/types.js +0 -1
  64. package/dist/tools/channel-new-session.js +0 -27
  65. package/dist/tools/channel-send-file.js +0 -27
  66. package/dist/tools/channel-target.js +0 -34
  67. package/dist/tools/cron-run.js +0 -20
  68. package/dist/tools/cron-upsert.js +0 -51
  69. package/dist/tools/gateway-dispatch-cron.js +0 -33
  70. package/dist/tools/gateway-status.js +0 -25
  71. package/dist/tools/schedule-cancel.js +0 -12
  72. package/dist/tools/schedule-format.js +0 -48
  73. package/dist/tools/schedule-list.js +0 -17
  74. package/dist/tools/schedule-once.js +0 -43
  75. package/dist/tools/schedule-status.js +0 -23
  76. package/dist/tools/telegram-send-test.js +0 -26
  77. package/dist/tools/telegram-status.js +0 -49
  78. package/dist/tools/time.js +0 -25
  79. package/dist/utils/error.js +0 -57
@@ -6,7 +6,7 @@ export declare class TelegramApiError extends Error {
6
6
  export declare class TelegramBotClient {
7
7
  private readonly botToken;
8
8
  constructor(botToken: string);
9
- getUpdates(offset: number | null, timeoutSeconds: number): Promise<TelegramUpdate[]>;
9
+ getUpdates(offset: number | null, timeoutSeconds: number, signal?: AbortSignal): Promise<TelegramUpdate[]>;
10
10
  getMe(): Promise<TelegramBotProfile>;
11
11
  getChat(chatId: string): Promise<TelegramChat>;
12
12
  getFile(fileId: string): Promise<TelegramFileRecord>;
@@ -6,6 +6,11 @@ import type { GatewayMailboxRuntime } from "../runtime/mailbox";
6
6
  import type { SqliteStore } from "../store/sqlite";
7
7
  import { type TelegramPollingClientLike } from "./client";
8
8
  import type { TelegramInboundMediaStore } from "./media";
9
+ type PollerTiming = {
10
+ timeoutFloorMs: number;
11
+ timeoutGraceMs: number;
12
+ stallGraceMs: number;
13
+ };
9
14
  export declare class TelegramPollingService {
10
15
  private readonly client;
11
16
  private readonly mailbox;
@@ -16,14 +21,24 @@ export declare class TelegramPollingService {
16
21
  private readonly mediaStore;
17
22
  private readonly questions;
18
23
  private readonly allowlist;
24
+ private readonly timing;
19
25
  private running;
26
+ private inFlightStartedAtMs;
27
+ private consecutiveFailures;
28
+ private recoveredAtMs;
20
29
  constructor(client: TelegramPollingClientLike, mailbox: GatewayMailboxRuntimeLike, store: SqliteStore, logger: BindingLoggerHost, config: Extract<TelegramConfig, {
21
30
  enabled: true;
22
- }>, mailboxRouter: GatewayMailboxRouter, mediaStore: TelegramInboundMediaStore, questions: GatewayQuestionRuntime);
31
+ }>, mailboxRouter: MailboxRouterLike, mediaStore: TelegramInboundMediaStoreLike, questions: GatewayQuestionRuntimeLike, timing?: Partial<PollerTiming>);
23
32
  start(): void;
24
33
  isRunning(): boolean;
34
+ currentPollStartedAtMs(): number | null;
35
+ requestTimeoutMs(): number;
36
+ recoveryRecordedAtMs(): number | null;
25
37
  private runLoop;
26
38
  private advanceOffset;
27
39
  }
28
40
  type GatewayMailboxRuntimeLike = Pick<GatewayMailboxRuntime, "enqueueInboundMessage">;
41
+ type MailboxRouterLike = Pick<GatewayMailboxRouter, "resolve">;
42
+ type TelegramInboundMediaStoreLike = Pick<TelegramInboundMediaStore, "materializeInboundMessage">;
43
+ type GatewayQuestionRuntimeLike = Pick<GatewayQuestionRuntime, "handleTelegramCallbackQuery">;
29
44
  export {};
@@ -13,6 +13,7 @@ type OpencodeEventStreamLike = {
13
13
  export type GatewayTelegramStatus = TelegramHealthSnapshot & {
14
14
  enabled: boolean;
15
15
  polling: boolean;
16
+ pollState: "disabled" | "idle" | "running" | "stalled" | "recovering";
16
17
  allowlistMode: "disabled" | "explicit";
17
18
  allowedChatsCount: number;
18
19
  allowedUsersCount: number;
@@ -32,6 +33,7 @@ export type TelegramSendTestResult = {
32
33
  mode: "oneshot" | "progressive";
33
34
  };
34
35
  type TelegramTextDeliveryLike = Pick<GatewayTextDelivery, "sendTest">;
36
+ type TelegramPollingStateLike = Pick<TelegramPollingService, "currentPollStartedAtMs" | "isRunning" | "recoveryRecordedAtMs" | "requestTimeoutMs" | "start">;
35
37
  export declare class GatewayTelegramRuntime {
36
38
  private readonly client;
37
39
  private readonly delivery;
@@ -40,7 +42,7 @@ export declare class GatewayTelegramRuntime {
40
42
  private readonly config;
41
43
  private readonly polling;
42
44
  private readonly opencodeEvents;
43
- constructor(client: TelegramRuntimeClientLike | null, delivery: TelegramTextDeliveryLike, store: SqliteStore, logger: BindingLoggerHost, config: TelegramConfig, polling: TelegramPollingService | null, opencodeEvents: OpencodeEventStreamLike);
45
+ constructor(client: TelegramRuntimeClientLike | null, delivery: TelegramTextDeliveryLike, store: SqliteStore, logger: BindingLoggerHost, config: TelegramConfig, polling: TelegramPollingStateLike | null, opencodeEvents: OpencodeEventStreamLike);
44
46
  isEnabled(): boolean;
45
47
  isPolling(): boolean;
46
48
  allowlistMode(): "disabled" | "explicit";
@@ -4,8 +4,12 @@ export type TelegramStreamingFallbackReason = "non_private_chat" | "progressive_
4
4
  export type TelegramHealthSnapshot = {
5
5
  updateOffset: number | null;
6
6
  lastPollSuccessMs: number | null;
7
+ lastPollStartedMs: number | null;
8
+ lastPollCompletedMs: number | null;
7
9
  lastPollErrorAtMs: number | null;
8
10
  lastPollErrorMessage: string | null;
11
+ lastPollTimeoutAtMs: number | null;
12
+ lastPollTimeoutMessage: string | null;
9
13
  lastSendSuccessMs: number | null;
10
14
  lastSendErrorAtMs: number | null;
11
15
  lastSendErrorMessage: string | null;
@@ -22,8 +26,11 @@ export type TelegramHealthSnapshot = {
22
26
  lastStreamFallbackReason: TelegramStreamingFallbackReason | null;
23
27
  };
24
28
  export declare function readTelegramHealthSnapshot(store: SqliteStore): TelegramHealthSnapshot;
29
+ export declare function recordTelegramPollStarted(store: SqliteStore, recordedAtMs: number): void;
30
+ export declare function recordTelegramPollCompleted(store: SqliteStore, recordedAtMs: number): void;
25
31
  export declare function recordTelegramPollSuccess(store: SqliteStore, recordedAtMs: number): void;
26
32
  export declare function recordTelegramPollFailure(store: SqliteStore, message: string, recordedAtMs: number): void;
33
+ export declare function recordTelegramPollTimeout(store: SqliteStore, message: string, recordedAtMs: number): void;
27
34
  export declare function recordTelegramSendSuccess(store: SqliteStore, recordedAtMs: number): void;
28
35
  export declare function recordTelegramSendFailure(store: SqliteStore, message: string, recordedAtMs: number): void;
29
36
  export declare function recordTelegramProbeSuccess(store: SqliteStore, bot: TelegramBotProfile, recordedAtMs: number): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-gateway",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "Gateway plugin for OpenCode",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1,4 +0,0 @@
1
- const GENERATED_NODE_ENTRYPOINT = new URL("../../generated/wasm/pkg/opencode_gateway_ffi.js", import.meta.url);
2
- export async function loadGatewayBindingModule() {
3
- return (await import(GENERATED_NODE_ENTRYPOINT.href));
4
- }
@@ -1 +0,0 @@
1
- export {};
package/dist/cli/args.js DELETED
@@ -1,53 +0,0 @@
1
- import { resolve } from "node:path";
2
- export function parseCliCommand(argv) {
3
- const [command, ...rest] = argv;
4
- if (!command || command === "help" || command === "--help" || command === "-h") {
5
- return { kind: "help" };
6
- }
7
- if (command !== "init" && command !== "doctor") {
8
- throw new Error(`unknown command: ${command}`);
9
- }
10
- let managed = false;
11
- let configDir = null;
12
- for (let index = 0; index < rest.length; index += 1) {
13
- const argument = rest[index];
14
- if (argument === "--managed") {
15
- managed = true;
16
- continue;
17
- }
18
- if (argument === "--config-dir") {
19
- const value = rest[index + 1];
20
- if (!value) {
21
- throw new Error("--config-dir requires a value");
22
- }
23
- configDir = resolve(value);
24
- index += 1;
25
- continue;
26
- }
27
- if (argument === "--help" || argument === "-h") {
28
- return { kind: "help" };
29
- }
30
- throw new Error(`unknown argument: ${argument}`);
31
- }
32
- if (managed && configDir !== null) {
33
- throw new Error("--managed cannot be combined with --config-dir");
34
- }
35
- return {
36
- kind: command,
37
- managed,
38
- configDir,
39
- };
40
- }
41
- export function formatCliHelp() {
42
- return [
43
- "opencode-gateway",
44
- "",
45
- "Commands:",
46
- " opencode-gateway init [--managed] [--config-dir <path>]",
47
- " opencode-gateway doctor [--managed] [--config-dir <path>]",
48
- "",
49
- "Defaults:",
50
- " init/doctor use OPENCODE_CONFIG_DIR when set, otherwise ~/.config/opencode",
51
- " --managed uses ~/.config/opencode-gateway/opencode",
52
- ].join("\n");
53
- }
@@ -1,49 +0,0 @@
1
- import { readFile } from "node:fs/promises";
2
- import { join } from "node:path";
3
- import { GATEWAY_CONFIG_FILE, resolveGatewayWorkspacePath } from "../config/paths";
4
- import { inspectGatewayPlugin, parseOpencodeConfig } from "./opencode-config";
5
- import { resolveOpencodeConfigFile } from "./opencode-config-file";
6
- import { pathExists, resolveCliConfigDir } from "./paths";
7
- export async function runDoctor(options, env) {
8
- const configDir = resolveCliConfigDir(options, env);
9
- const gatewayConfigPath = join(configDir, GATEWAY_CONFIG_FILE);
10
- const workspaceDirPath = resolveGatewayWorkspacePath(gatewayConfigPath);
11
- const opencodeConfig = await resolveOpencodeConfigFile(configDir);
12
- const opencodeStatus = await inspectOpencodeConfig(opencodeConfig.path);
13
- const gatewayOverride = env.OPENCODE_GATEWAY_CONFIG?.trim() || null;
14
- console.log("doctor report");
15
- console.log(` config dir: ${configDir}`);
16
- console.log(` opencode config: ${await describePath(opencodeConfig.path)}`);
17
- console.log(` gateway config: ${await describePath(gatewayConfigPath)}`);
18
- console.log(` gateway workspace: ${await describePath(workspaceDirPath)}`);
19
- console.log(` gateway config override: ${gatewayOverride ?? "not set"}`);
20
- console.log(` plugin configured: ${opencodeStatus.pluginConfigured}`);
21
- console.log(` TELEGRAM_BOT_TOKEN: ${env.TELEGRAM_BOT_TOKEN?.trim() ? "set" : "missing"}`);
22
- if (opencodeStatus.error !== null) {
23
- console.log(` opencode config error: ${opencodeStatus.error}`);
24
- }
25
- }
26
- async function describePath(path) {
27
- return (await pathExists(path)) ? `present at ${path}` : `missing at ${path}`;
28
- }
29
- async function inspectOpencodeConfig(path) {
30
- if (!(await pathExists(path))) {
31
- return {
32
- pluginConfigured: "no",
33
- error: null,
34
- };
35
- }
36
- try {
37
- const parsed = parseOpencodeConfig(await readFile(path, "utf8"), path);
38
- return {
39
- pluginConfigured: inspectGatewayPlugin(parsed),
40
- error: null,
41
- };
42
- }
43
- catch (error) {
44
- return {
45
- pluginConfigured: "unknown",
46
- error: error instanceof Error ? error.message : String(error),
47
- };
48
- }
49
- }
package/dist/cli/init.js DELETED
@@ -1,40 +0,0 @@
1
- import { mkdir, readFile, writeFile } from "node:fs/promises";
2
- import { dirname, join } from "node:path";
3
- import { defaultGatewayStateDbPath, GATEWAY_CONFIG_FILE, resolveGatewayWorkspacePath } from "../config/paths";
4
- import { createDefaultOpencodeConfig, ensureGatewayPlugin, parseOpencodeConfig, stringifyOpencodeConfig, } from "./opencode-config";
5
- import { resolveOpencodeConfigFile } from "./opencode-config-file";
6
- import { pathExists, resolveCliConfigDir } from "./paths";
7
- import { buildGatewayConfigTemplate } from "./templates";
8
- export async function runInit(options, env) {
9
- const configDir = resolveCliConfigDir(options, env);
10
- const gatewayConfigPath = join(configDir, GATEWAY_CONFIG_FILE);
11
- const workspaceDirPath = resolveGatewayWorkspacePath(gatewayConfigPath);
12
- const opencodeConfig = await resolveOpencodeConfigFile(configDir);
13
- const opencodeConfigPath = opencodeConfig.path;
14
- await mkdir(configDir, { recursive: true });
15
- await mkdir(workspaceDirPath, { recursive: true });
16
- let opencodeStatus = "already present";
17
- if (!opencodeConfig.exists) {
18
- await writeFile(opencodeConfigPath, stringifyOpencodeConfig(createDefaultOpencodeConfig(options.managed)));
19
- opencodeStatus = "created";
20
- }
21
- else {
22
- const source = await readFile(opencodeConfigPath, "utf8");
23
- const parsed = parseOpencodeConfig(source, opencodeConfigPath);
24
- const next = ensureGatewayPlugin(parsed);
25
- if (next.changed) {
26
- await writeFile(opencodeConfigPath, stringifyOpencodeConfig(next.document));
27
- opencodeStatus = "updated";
28
- }
29
- }
30
- let gatewayStatus = "already present";
31
- if (!(await pathExists(gatewayConfigPath))) {
32
- await mkdir(dirname(gatewayConfigPath), { recursive: true });
33
- await writeFile(gatewayConfigPath, buildGatewayConfigTemplate(defaultGatewayStateDbPath(env)));
34
- gatewayStatus = "created";
35
- }
36
- console.log(`config dir: ${configDir}`);
37
- console.log(`opencode config: ${opencodeConfigPath} (${opencodeStatus})`);
38
- console.log(`gateway config: ${gatewayConfigPath} (${gatewayStatus})`);
39
- console.log(`gateway workspace: ${workspaceDirPath} (ready)`);
40
- }
@@ -1,18 +0,0 @@
1
- import { join } from "node:path";
2
- import { OPENCODE_CONFIG_FILE_CANDIDATES, OPENCODE_CONFIG_FILE_JSONC } from "../config/paths";
3
- import { pathExists } from "./paths";
4
- export async function resolveOpencodeConfigFile(configDir) {
5
- for (const fileName of OPENCODE_CONFIG_FILE_CANDIDATES) {
6
- const path = join(configDir, fileName);
7
- if (await pathExists(path)) {
8
- return {
9
- path,
10
- exists: true,
11
- };
12
- }
13
- }
14
- return {
15
- path: join(configDir, OPENCODE_CONFIG_FILE_JSONC),
16
- exists: false,
17
- };
18
- }
@@ -1,194 +0,0 @@
1
- const OPENCODE_SCHEMA_URL = "https://opencode.ai/config.json";
2
- const PACKAGE_NAME = "opencode-gateway";
3
- const PACKAGE_SPEC = "opencode-gateway@latest";
4
- export function createDefaultOpencodeConfig(managed) {
5
- const document = {
6
- $schema: OPENCODE_SCHEMA_URL,
7
- plugin: [PACKAGE_SPEC],
8
- };
9
- if (managed) {
10
- document.server = {
11
- hostname: "127.0.0.1",
12
- port: 4096,
13
- };
14
- }
15
- return document;
16
- }
17
- export function ensureGatewayPlugin(document) {
18
- const plugins = readPluginArray(document);
19
- if (plugins === undefined) {
20
- return {
21
- changed: true,
22
- document: {
23
- ...document,
24
- plugin: [PACKAGE_SPEC],
25
- },
26
- };
27
- }
28
- if (plugins.includes(PACKAGE_SPEC)) {
29
- return {
30
- changed: false,
31
- document,
32
- };
33
- }
34
- return {
35
- changed: true,
36
- document: {
37
- ...document,
38
- plugin: [...plugins, PACKAGE_SPEC],
39
- },
40
- };
41
- }
42
- export function parseOpencodeConfig(source, path) {
43
- let parsed;
44
- try {
45
- parsed = JSON.parse(toStrictJson(source));
46
- }
47
- catch (error) {
48
- throw new Error(`failed to parse opencode config ${path}: ${formatError(error)}`);
49
- }
50
- if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
51
- throw new Error(`opencode config ${path} must decode to a JSON object`);
52
- }
53
- return parsed;
54
- }
55
- export function stringifyOpencodeConfig(document) {
56
- return `${JSON.stringify(document, null, 2)}\n`;
57
- }
58
- export function inspectGatewayPlugin(document) {
59
- const plugins = readPluginArray(document);
60
- if (plugins === undefined) {
61
- return "no";
62
- }
63
- if (plugins.includes(PACKAGE_SPEC)) {
64
- return "yes";
65
- }
66
- return plugins.some((entry) => isGatewayPluginReference(entry)) ? "needs_update" : "no";
67
- }
68
- function formatError(error) {
69
- return error instanceof Error ? error.message : String(error);
70
- }
71
- function readPluginArray(document) {
72
- const plugins = document.plugin;
73
- if (plugins === undefined) {
74
- return undefined;
75
- }
76
- if (!Array.isArray(plugins)) {
77
- throw new Error("opencode config field `plugin` must be an array when present");
78
- }
79
- const normalized = [];
80
- for (const [index, entry] of plugins.entries()) {
81
- if (typeof entry !== "string") {
82
- throw new Error(`opencode config field \`plugin[${index}]\` must be a string`);
83
- }
84
- normalized.push(entry);
85
- }
86
- return normalized;
87
- }
88
- function toStrictJson(source) {
89
- return stripTrailingCommas(stripJsonComments(source));
90
- }
91
- function stripJsonComments(source) {
92
- let result = "";
93
- let inString = false;
94
- let escaped = false;
95
- let inLineComment = false;
96
- let inBlockComment = false;
97
- for (let index = 0; index < source.length; index += 1) {
98
- const current = source[index];
99
- const next = source[index + 1];
100
- if (inLineComment) {
101
- if (current === "\n") {
102
- inLineComment = false;
103
- result += current;
104
- }
105
- continue;
106
- }
107
- if (inBlockComment) {
108
- if (current === "*" && next === "/") {
109
- inBlockComment = false;
110
- index += 1;
111
- }
112
- else if (current === "\n") {
113
- result += current;
114
- }
115
- continue;
116
- }
117
- if (inString) {
118
- result += current;
119
- if (escaped) {
120
- escaped = false;
121
- }
122
- else if (current === "\\") {
123
- escaped = true;
124
- }
125
- else if (current === '"') {
126
- inString = false;
127
- }
128
- continue;
129
- }
130
- if (current === '"') {
131
- inString = true;
132
- result += current;
133
- continue;
134
- }
135
- if (current === "/" && next === "/") {
136
- inLineComment = true;
137
- index += 1;
138
- continue;
139
- }
140
- if (current === "/" && next === "*") {
141
- inBlockComment = true;
142
- index += 1;
143
- continue;
144
- }
145
- result += current;
146
- }
147
- return result;
148
- }
149
- function stripTrailingCommas(source) {
150
- let result = "";
151
- let inString = false;
152
- let escaped = false;
153
- for (let index = 0; index < source.length; index += 1) {
154
- const current = source[index];
155
- if (inString) {
156
- result += current;
157
- if (escaped) {
158
- escaped = false;
159
- }
160
- else if (current === "\\") {
161
- escaped = true;
162
- }
163
- else if (current === '"') {
164
- inString = false;
165
- }
166
- continue;
167
- }
168
- if (current === '"') {
169
- inString = true;
170
- result += current;
171
- continue;
172
- }
173
- if (current === ",") {
174
- const nextSignificant = findNextSignificantCharacter(source, index + 1);
175
- if (nextSignificant === "]" || nextSignificant === "}") {
176
- continue;
177
- }
178
- }
179
- result += current;
180
- }
181
- return result;
182
- }
183
- function findNextSignificantCharacter(source, startIndex) {
184
- for (let index = startIndex; index < source.length; index += 1) {
185
- const current = source[index];
186
- if (!/\s/.test(current)) {
187
- return current;
188
- }
189
- }
190
- return null;
191
- }
192
- function isGatewayPluginReference(entry) {
193
- return entry === PACKAGE_NAME || entry.startsWith(`${PACKAGE_NAME}@`);
194
- }
package/dist/cli/paths.js DELETED
@@ -1,22 +0,0 @@
1
- import { constants } from "node:fs";
2
- import { access } from "node:fs/promises";
3
- import { resolve } from "node:path";
4
- import { resolveManagedOpencodeConfigDir, resolveOpencodeConfigDir } from "../config/paths";
5
- export function resolveCliConfigDir(options, env) {
6
- if (options.configDir !== null) {
7
- return resolve(options.configDir);
8
- }
9
- if (options.managed) {
10
- return resolveManagedOpencodeConfigDir(env);
11
- }
12
- return resolveOpencodeConfigDir(env);
13
- }
14
- export async function pathExists(path) {
15
- try {
16
- await access(path, constants.F_OK);
17
- return true;
18
- }
19
- catch {
20
- return false;
21
- }
22
- }
@@ -1,41 +0,0 @@
1
- export function buildGatewayConfigTemplate(stateDbPath) {
2
- return [
3
- "# Opencode Gateway configuration",
4
- "# Fill in secrets and provider details before enabling real integrations.",
5
- "",
6
- "[gateway]",
7
- `state_db = "${escapeTomlString(stateDbPath)}"`,
8
- '# log_level = "warn"',
9
- "",
10
- "[cron]",
11
- "enabled = true",
12
- "tick_seconds = 5",
13
- "max_concurrent_runs = 1",
14
- '# timezone = "Asia/Shanghai"',
15
- "",
16
- "[channels.telegram]",
17
- "enabled = false",
18
- 'bot_token_env = "TELEGRAM_BOT_TOKEN"',
19
- "poll_timeout_seconds = 25",
20
- "allowed_chats = []",
21
- "allowed_users = []",
22
- "",
23
- "# Optional long-lived memory sources injected into gateway-managed sessions.",
24
- "# Relative paths are resolved from opencode-gateway-workspace.",
25
- "#",
26
- "# [[memory.entries]]",
27
- '# path = "memory/project.md"',
28
- '# description = "Project conventions and long-lived context"',
29
- "# inject_content = true",
30
- "#",
31
- "# [[memory.entries]]",
32
- '# path = "memory/notes"',
33
- '# description = "Domain notes and operating docs"',
34
- "# inject_markdown_contents = true",
35
- '# globs = ["**/*.rs", "notes/**/*.txt"]',
36
- "",
37
- ].join("\n");
38
- }
39
- function escapeTomlString(value) {
40
- return value.replaceAll("\\", "\\\\").replaceAll('"', '\\"');
41
- }
@@ -1,52 +0,0 @@
1
- export function parseCronConfig(value) {
2
- const table = readCronTable(value);
3
- return {
4
- enabled: readBoolean(table.enabled, "cron.enabled", true),
5
- tickSeconds: readPositiveInteger(table.tick_seconds, "cron.tick_seconds", 5),
6
- maxConcurrentRuns: readPositiveInteger(table.max_concurrent_runs, "cron.max_concurrent_runs", 1),
7
- timezone: readOptionalString(table.timezone, "cron.timezone"),
8
- };
9
- }
10
- function readCronTable(value) {
11
- if (value === undefined) {
12
- return {};
13
- }
14
- if (value === null || typeof value !== "object" || Array.isArray(value)) {
15
- throw new Error("cron must be a table when present");
16
- }
17
- return value;
18
- }
19
- function readBoolean(value, field, fallback) {
20
- if (value === undefined) {
21
- return fallback;
22
- }
23
- if (typeof value !== "boolean") {
24
- throw new Error(`${field} must be a boolean when present`);
25
- }
26
- return value;
27
- }
28
- function readPositiveInteger(value, field, fallback) {
29
- if (value === undefined) {
30
- return fallback;
31
- }
32
- if (typeof value !== "number" || !Number.isInteger(value)) {
33
- throw new Error(`${field} must be an integer when present`);
34
- }
35
- if (value < 1) {
36
- throw new Error(`${field} must be greater than or equal to 1`);
37
- }
38
- return value;
39
- }
40
- function readOptionalString(value, field) {
41
- if (value === undefined) {
42
- return null;
43
- }
44
- if (typeof value !== "string") {
45
- throw new Error(`${field} must be a string when present`);
46
- }
47
- const trimmed = value.trim();
48
- if (trimmed.length === 0) {
49
- throw new Error(`${field} must not be empty when present`);
50
- }
51
- return trimmed;
52
- }