@coinseeker/opencode-telegram-plugin 1.1.1 → 1.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 +4 -2
- package/dist/telegram-remote.js +262 -43
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,14 +15,16 @@ Configure the npm package in `~/.config/opencode/opencode.json`:
|
|
|
15
15
|
|
|
16
16
|
```json
|
|
17
17
|
{
|
|
18
|
-
"plugin": ["@coinseeker/opencode-telegram-plugin@1.1.
|
|
18
|
+
"plugin": ["@coinseeker/opencode-telegram-plugin@1.1.2"]
|
|
19
19
|
}
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
Current stable version: `@coinseeker/opencode-telegram-plugin@1.1.
|
|
22
|
+
Current stable version: `@coinseeker/opencode-telegram-plugin@1.1.2`.
|
|
23
23
|
|
|
24
24
|
Restart OpenCode after editing the config. OpenCode resolves npm package plugins on startup.
|
|
25
25
|
|
|
26
|
+
To update an existing install, replace the previous pinned package entry with `@coinseeker/opencode-telegram-plugin@1.1.2`, keep the rest of the `plugin` array unchanged, and restart OpenCode.
|
|
27
|
+
|
|
26
28
|
## Configure Telegram
|
|
27
29
|
|
|
28
30
|
Create `~/.config/opencode/telegram-remote/.env`:
|
package/dist/telegram-remote.js
CHANGED
|
@@ -1560,7 +1560,7 @@ var ROOT_IDLE_RECHECK_DELAY_MS = 2500;
|
|
|
1560
1560
|
var DEFERRED_PARENT_CONFIRM_DELAY_MS = 2500;
|
|
1561
1561
|
var deferredConfirmTimers = /* @__PURE__ */ new Map();
|
|
1562
1562
|
function sleep(ms) {
|
|
1563
|
-
return new Promise((
|
|
1563
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
1564
1564
|
}
|
|
1565
1565
|
function agentFinishedMessage(title, agent) {
|
|
1566
1566
|
const base = title ? `Agent has finished: ${title}` : "Agent has finished.";
|
|
@@ -1913,48 +1913,170 @@ ${body}
|
|
|
1913
1913
|
|
|
1914
1914
|
// src/lib/plan-readiness.ts
|
|
1915
1915
|
import { access, readFile as readFile5, readdir as readdir6, stat as stat2 } from "fs/promises";
|
|
1916
|
-
import { join as join6 } from "path";
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1916
|
+
import { basename, isAbsolute, join as join6, relative, resolve } from "path";
|
|
1917
|
+
function asRecord2(value) {
|
|
1918
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1919
|
+
return value;
|
|
1920
|
+
}
|
|
1921
|
+
function stringArray(value) {
|
|
1922
|
+
if (!Array.isArray(value)) return [];
|
|
1923
|
+
return value.filter((item) => typeof item === "string");
|
|
1924
|
+
}
|
|
1925
|
+
function optionalString(value) {
|
|
1926
|
+
return typeof value === "string" ? value : void 0;
|
|
1927
|
+
}
|
|
1928
|
+
function normalizeBoulderWork(value) {
|
|
1929
|
+
const record = asRecord2(value);
|
|
1930
|
+
if (!record || typeof record.active_plan !== "string") return void 0;
|
|
1931
|
+
const work = {
|
|
1932
|
+
activePlan: record.active_plan,
|
|
1933
|
+
sessionIds: stringArray(record.session_ids)
|
|
1934
|
+
};
|
|
1935
|
+
const planName = optionalString(record.plan_name);
|
|
1936
|
+
if (planName !== void 0) work.planName = planName;
|
|
1937
|
+
const status = optionalString(record.status);
|
|
1938
|
+
if (status !== void 0) work.status = status;
|
|
1939
|
+
const startedAt = optionalString(record.started_at);
|
|
1940
|
+
if (startedAt !== void 0) work.startedAt = startedAt;
|
|
1941
|
+
const updatedAt = optionalString(record.updated_at);
|
|
1942
|
+
if (updatedAt !== void 0) work.updatedAt = updatedAt;
|
|
1943
|
+
const worktreePath = optionalString(record.worktree_path);
|
|
1944
|
+
if (worktreePath !== void 0) work.worktreePath = worktreePath;
|
|
1945
|
+
return work;
|
|
1946
|
+
}
|
|
1947
|
+
function normalizeBoulderState(value) {
|
|
1948
|
+
const record = asRecord2(value);
|
|
1949
|
+
if (!record) return void 0;
|
|
1950
|
+
const state = { sessionIds: stringArray(record.session_ids) };
|
|
1951
|
+
const activePlan = optionalString(record.active_plan);
|
|
1952
|
+
if (activePlan !== void 0) state.activePlan = activePlan;
|
|
1953
|
+
const planName = optionalString(record.plan_name);
|
|
1954
|
+
if (planName !== void 0) state.planName = planName;
|
|
1955
|
+
const status = optionalString(record.status);
|
|
1956
|
+
if (status !== void 0) state.status = status;
|
|
1957
|
+
const startedAt = optionalString(record.started_at);
|
|
1958
|
+
if (startedAt !== void 0) state.startedAt = startedAt;
|
|
1959
|
+
const updatedAt = optionalString(record.updated_at);
|
|
1960
|
+
if (updatedAt !== void 0) state.updatedAt = updatedAt;
|
|
1961
|
+
const worktreePath = optionalString(record.worktree_path);
|
|
1962
|
+
if (worktreePath !== void 0) state.worktreePath = worktreePath;
|
|
1963
|
+
const activeWorkId = optionalString(record.active_work_id);
|
|
1964
|
+
if (activeWorkId !== void 0) state.activeWorkId = activeWorkId;
|
|
1965
|
+
const worksRecord = asRecord2(record.works);
|
|
1966
|
+
if (worksRecord) {
|
|
1967
|
+
const works = {};
|
|
1968
|
+
for (const [workId, rawWork] of Object.entries(worksRecord)) {
|
|
1969
|
+
const work = normalizeBoulderWork(rawWork);
|
|
1970
|
+
if (work) works[workId] = work;
|
|
1971
|
+
}
|
|
1972
|
+
if (Object.keys(works).length > 0) state.works = works;
|
|
1973
|
+
}
|
|
1974
|
+
return state;
|
|
1975
|
+
}
|
|
1976
|
+
async function readBoulderState(boulderPath) {
|
|
1977
|
+
let text;
|
|
1922
1978
|
try {
|
|
1923
|
-
await
|
|
1979
|
+
text = await readFile5(boulderPath, "utf8");
|
|
1980
|
+
} catch (err) {
|
|
1981
|
+
if (err instanceof Error && "code" in err && err.code === "ENOENT") {
|
|
1982
|
+
return { exists: false };
|
|
1983
|
+
}
|
|
1984
|
+
return { exists: true };
|
|
1985
|
+
}
|
|
1986
|
+
try {
|
|
1987
|
+
return { exists: true, state: normalizeBoulderState(JSON.parse(text)) };
|
|
1924
1988
|
} catch {
|
|
1925
|
-
return {
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1989
|
+
return { exists: true };
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
function mirrorWorkFromState(state) {
|
|
1993
|
+
if (!state.activePlan) return void 0;
|
|
1994
|
+
const work = {
|
|
1995
|
+
activePlan: state.activePlan,
|
|
1996
|
+
sessionIds: state.sessionIds
|
|
1997
|
+
};
|
|
1998
|
+
if (state.planName !== void 0) work.planName = state.planName;
|
|
1999
|
+
if (state.status !== void 0) work.status = state.status;
|
|
2000
|
+
if (state.startedAt !== void 0) work.startedAt = state.startedAt;
|
|
2001
|
+
if (state.updatedAt !== void 0) work.updatedAt = state.updatedAt;
|
|
2002
|
+
if (state.worktreePath !== void 0) work.worktreePath = state.worktreePath;
|
|
2003
|
+
return work;
|
|
2004
|
+
}
|
|
2005
|
+
function boulderWorks(state) {
|
|
2006
|
+
if (state.works) return Object.values(state.works);
|
|
2007
|
+
const mirrorWork = mirrorWorkFromState(state);
|
|
2008
|
+
return mirrorWork ? [mirrorWork] : [];
|
|
2009
|
+
}
|
|
2010
|
+
function parseIsoToMs(value) {
|
|
2011
|
+
if (!value) return 0;
|
|
2012
|
+
const ms = Date.parse(value);
|
|
2013
|
+
return Number.isNaN(ms) ? 0 : ms;
|
|
2014
|
+
}
|
|
2015
|
+
function findBoulderWorkForSession(state, sessionId) {
|
|
2016
|
+
const works = boulderWorks(state).filter((work) => work.sessionIds.includes(sessionId)).sort(
|
|
2017
|
+
(left, right) => parseIsoToMs(right.updatedAt ?? right.startedAt) - parseIsoToMs(left.updatedAt ?? left.startedAt)
|
|
2018
|
+
);
|
|
2019
|
+
if (works[0]) return works[0];
|
|
2020
|
+
const mirrorWork = mirrorWorkFromState(state);
|
|
2021
|
+
if (mirrorWork && state.sessionIds.includes(sessionId)) return mirrorWork;
|
|
2022
|
+
return void 0;
|
|
2023
|
+
}
|
|
2024
|
+
function isActiveBoulderWork(work) {
|
|
2025
|
+
return work.status !== "completed" && work.status !== "abandoned";
|
|
2026
|
+
}
|
|
2027
|
+
function resolveTrackedPath(baseDirectory, trackedPath) {
|
|
2028
|
+
return isAbsolute(trackedPath) ? resolve(trackedPath) : resolve(baseDirectory, trackedPath);
|
|
2029
|
+
}
|
|
2030
|
+
async function resolveBoulderPlanPath(projectRoot, work) {
|
|
2031
|
+
const absolutePlanPath = resolveTrackedPath(projectRoot, work.activePlan);
|
|
2032
|
+
const worktreePath = work.worktreePath?.trim();
|
|
2033
|
+
if (!worktreePath) return absolutePlanPath;
|
|
2034
|
+
const relativePlanPath = relative(resolve(projectRoot), absolutePlanPath);
|
|
2035
|
+
if (relativePlanPath.length === 0 || relativePlanPath.startsWith("..") || isAbsolute(relativePlanPath)) {
|
|
2036
|
+
return absolutePlanPath;
|
|
1930
2037
|
}
|
|
2038
|
+
const worktreePlanPath = resolve(resolveTrackedPath(projectRoot, worktreePath), relativePlanPath);
|
|
1931
2039
|
try {
|
|
1932
|
-
await access(
|
|
1933
|
-
return
|
|
1934
|
-
ready: false,
|
|
1935
|
-
reason: "boulder-active",
|
|
1936
|
-
detail: `${boulderPath} exists`
|
|
1937
|
-
};
|
|
2040
|
+
await access(worktreePlanPath);
|
|
2041
|
+
return worktreePlanPath;
|
|
1938
2042
|
} catch {
|
|
2043
|
+
return absolutePlanPath;
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
function planNameFromPath(planPath) {
|
|
2047
|
+
return basename(planPath, ".md");
|
|
2048
|
+
}
|
|
2049
|
+
function normalizePlanToken(value) {
|
|
2050
|
+
return value.normalize("NFKD").toLowerCase().replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9가-힣]+/g, "-").replace(/^-+|-+$/g, "");
|
|
2051
|
+
}
|
|
2052
|
+
function selectPlanByHint(candidates, planHint) {
|
|
2053
|
+
if (!planHint) return void 0;
|
|
2054
|
+
const normalizedHint = normalizePlanToken(planHint);
|
|
2055
|
+
if (!normalizedHint) return void 0;
|
|
2056
|
+
return candidates.find((candidate) => {
|
|
2057
|
+
const planName = candidate.name.replace(/\.md$/, "");
|
|
2058
|
+
return normalizePlanToken(planName) === normalizedHint;
|
|
2059
|
+
});
|
|
2060
|
+
}
|
|
2061
|
+
function resolvePlanPathHint(projectRoot, planPath) {
|
|
2062
|
+
if (!planPath) return void 0;
|
|
2063
|
+
const resolvedPath = isAbsolute(planPath) ? resolve(planPath) : resolve(projectRoot, planPath);
|
|
2064
|
+
const plansRoot = resolve(projectRoot, ".omo", "plans");
|
|
2065
|
+
const relativePlanPath = relative(plansRoot, resolvedPath);
|
|
2066
|
+
if (!resolvedPath.endsWith(".md") || relativePlanPath.length === 0 || relativePlanPath.startsWith("..") || isAbsolute(relativePlanPath)) {
|
|
2067
|
+
return void 0;
|
|
1939
2068
|
}
|
|
2069
|
+
return resolvedPath;
|
|
2070
|
+
}
|
|
2071
|
+
async function getPlanFiles(plansDir) {
|
|
1940
2072
|
let planFiles = [];
|
|
1941
2073
|
try {
|
|
1942
2074
|
const entries = await readdir6(plansDir);
|
|
1943
2075
|
planFiles = entries.filter((e) => e.endsWith(".md"));
|
|
1944
2076
|
} catch {
|
|
1945
|
-
return
|
|
1946
|
-
ready: false,
|
|
1947
|
-
reason: "no-plans",
|
|
1948
|
-
detail: `${plansDir} not found or empty`
|
|
1949
|
-
};
|
|
1950
|
-
}
|
|
1951
|
-
if (planFiles.length === 0) {
|
|
1952
|
-
return {
|
|
1953
|
-
ready: false,
|
|
1954
|
-
reason: "no-plans",
|
|
1955
|
-
detail: `No .md files in ${plansDir}`
|
|
1956
|
-
};
|
|
2077
|
+
return void 0;
|
|
1957
2078
|
}
|
|
2079
|
+
if (planFiles.length === 0) return [];
|
|
1958
2080
|
const stats = await Promise.all(
|
|
1959
2081
|
planFiles.map(async (f) => {
|
|
1960
2082
|
const full = join6(plansDir, f);
|
|
@@ -1962,9 +2084,20 @@ async function checkPlanReadiness(args) {
|
|
|
1962
2084
|
return { path: full, name: f, mtime: s.mtime.getTime() };
|
|
1963
2085
|
})
|
|
1964
2086
|
);
|
|
1965
|
-
stats.sort((a, b) => b.mtime - a.mtime);
|
|
1966
|
-
|
|
1967
|
-
|
|
2087
|
+
return stats.sort((a, b) => b.mtime - a.mtime);
|
|
2088
|
+
}
|
|
2089
|
+
async function readPlanProgress(planPath, planName, boulderActive = false) {
|
|
2090
|
+
let content;
|
|
2091
|
+
try {
|
|
2092
|
+
content = await readFile5(planPath, "utf8");
|
|
2093
|
+
} catch {
|
|
2094
|
+
return {
|
|
2095
|
+
ready: false,
|
|
2096
|
+
reason: "no-plans",
|
|
2097
|
+
detail: `${planPath} not found`,
|
|
2098
|
+
...boulderActive ? { boulderActive } : {}
|
|
2099
|
+
};
|
|
2100
|
+
}
|
|
1968
2101
|
const totalMatches = content.match(/^- \[[ xX]\]/gm) ?? [];
|
|
1969
2102
|
const completedMatches = content.match(/^- \[[xX]\]/gm) ?? [];
|
|
1970
2103
|
const total = totalMatches.length;
|
|
@@ -1973,24 +2106,99 @@ async function checkPlanReadiness(args) {
|
|
|
1973
2106
|
return {
|
|
1974
2107
|
ready: false,
|
|
1975
2108
|
reason: "plan-empty",
|
|
1976
|
-
detail: `${
|
|
2109
|
+
detail: `${planName}: no checkboxes found`,
|
|
2110
|
+
...boulderActive ? { boulderActive } : {}
|
|
1977
2111
|
};
|
|
1978
2112
|
}
|
|
1979
2113
|
if (completed >= total) {
|
|
1980
2114
|
return {
|
|
1981
2115
|
ready: false,
|
|
1982
2116
|
reason: "all-plans-complete",
|
|
1983
|
-
detail: `${
|
|
2117
|
+
detail: `${planName}: ${completed}/${total} complete`,
|
|
2118
|
+
...boulderActive ? { boulderActive } : {}
|
|
1984
2119
|
};
|
|
1985
2120
|
}
|
|
1986
2121
|
return {
|
|
1987
2122
|
ready: true,
|
|
1988
|
-
planPath
|
|
1989
|
-
planName
|
|
2123
|
+
planPath,
|
|
2124
|
+
planName,
|
|
1990
2125
|
total,
|
|
1991
|
-
completed
|
|
2126
|
+
completed,
|
|
2127
|
+
...boulderActive ? { boulderActive } : {}
|
|
1992
2128
|
};
|
|
1993
2129
|
}
|
|
2130
|
+
async function checkPlanReadiness(args) {
|
|
2131
|
+
const { projectRoot, sessionId } = args;
|
|
2132
|
+
const allowLatestFallback = args.allowLatestFallback ?? sessionId === void 0;
|
|
2133
|
+
const omoDir = join6(projectRoot, ".omo");
|
|
2134
|
+
const plansDir = join6(omoDir, "plans");
|
|
2135
|
+
const boulderPath = join6(omoDir, "boulder.json");
|
|
2136
|
+
try {
|
|
2137
|
+
await access(omoDir);
|
|
2138
|
+
} catch {
|
|
2139
|
+
return {
|
|
2140
|
+
ready: false,
|
|
2141
|
+
reason: "no-omo-dir",
|
|
2142
|
+
detail: `${omoDir} does not exist`
|
|
2143
|
+
};
|
|
2144
|
+
}
|
|
2145
|
+
const boulder = await readBoulderState(boulderPath);
|
|
2146
|
+
const projectBoulderActive = boulder.exists;
|
|
2147
|
+
if (boulder.exists && sessionId === void 0) {
|
|
2148
|
+
return {
|
|
2149
|
+
ready: false,
|
|
2150
|
+
reason: "boulder-active",
|
|
2151
|
+
detail: `${boulderPath} exists`,
|
|
2152
|
+
boulderActive: true
|
|
2153
|
+
};
|
|
2154
|
+
}
|
|
2155
|
+
if (boulder.state && sessionId !== void 0) {
|
|
2156
|
+
const work = findBoulderWorkForSession(boulder.state, sessionId);
|
|
2157
|
+
if (work) {
|
|
2158
|
+
const planPath = await resolveBoulderPlanPath(projectRoot, work);
|
|
2159
|
+
return readPlanProgress(
|
|
2160
|
+
planPath,
|
|
2161
|
+
work.planName ?? planNameFromPath(planPath),
|
|
2162
|
+
isActiveBoulderWork(work)
|
|
2163
|
+
);
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
const explicitPlanPath = resolvePlanPathHint(projectRoot, args.planPath);
|
|
2167
|
+
if (explicitPlanPath) {
|
|
2168
|
+
return readPlanProgress(explicitPlanPath, planNameFromPath(explicitPlanPath), projectBoulderActive);
|
|
2169
|
+
}
|
|
2170
|
+
const stats = await getPlanFiles(plansDir);
|
|
2171
|
+
if (stats === void 0) {
|
|
2172
|
+
return {
|
|
2173
|
+
ready: false,
|
|
2174
|
+
reason: "no-plans",
|
|
2175
|
+
detail: `${plansDir} not found or empty`,
|
|
2176
|
+
...projectBoulderActive ? { boulderActive: true } : {}
|
|
2177
|
+
};
|
|
2178
|
+
}
|
|
2179
|
+
if (stats.length === 0) {
|
|
2180
|
+
return {
|
|
2181
|
+
ready: false,
|
|
2182
|
+
reason: "no-plans",
|
|
2183
|
+
detail: `No .md files in ${plansDir}`,
|
|
2184
|
+
...projectBoulderActive ? { boulderActive: true } : {}
|
|
2185
|
+
};
|
|
2186
|
+
}
|
|
2187
|
+
const hinted = selectPlanByHint(stats, args.planHint);
|
|
2188
|
+
if (hinted) {
|
|
2189
|
+
return readPlanProgress(hinted.path, hinted.name.replace(/\.md$/, ""), projectBoulderActive);
|
|
2190
|
+
}
|
|
2191
|
+
if (!allowLatestFallback) {
|
|
2192
|
+
return {
|
|
2193
|
+
ready: false,
|
|
2194
|
+
reason: "no-session-plan",
|
|
2195
|
+
detail: `No plan associated with session ${sessionId ?? "missing"}`,
|
|
2196
|
+
...projectBoulderActive ? { boulderActive: true } : {}
|
|
2197
|
+
};
|
|
2198
|
+
}
|
|
2199
|
+
const latest = stats[0];
|
|
2200
|
+
return readPlanProgress(latest.path, latest.name.replace(/\.md$/, ""), projectBoulderActive);
|
|
2201
|
+
}
|
|
1994
2202
|
async function recheckSessionIdle(client, sessionId) {
|
|
1995
2203
|
const result = await client.session.status();
|
|
1996
2204
|
const statuses = result.data ?? {};
|
|
@@ -2052,6 +2260,8 @@ function planReadinessKorean(result) {
|
|
|
2052
2260
|
}
|
|
2053
2261
|
case "boulder-active":
|
|
2054
2262
|
return "boulder \uD65C\uC131";
|
|
2263
|
+
case "no-session-plan":
|
|
2264
|
+
return "\uC138\uC158 \uC5F0\uACB0 plan \uC5C6\uC74C";
|
|
2055
2265
|
}
|
|
2056
2266
|
}
|
|
2057
2267
|
function planLine(result) {
|
|
@@ -2061,7 +2271,7 @@ function planLine(result) {
|
|
|
2061
2271
|
return `<b>\uD50C\uB79C \uC0C1\uD0DC</b>: ${planReadinessKorean(result)}`;
|
|
2062
2272
|
}
|
|
2063
2273
|
function boulderLine(result) {
|
|
2064
|
-
const active = !result.ready && result.reason === "boulder-active";
|
|
2274
|
+
const active = result.boulderActive === true || !result.ready && result.reason === "boulder-active";
|
|
2065
2275
|
return active ? "<b>Boulder</b>: \uD65C\uC131" : "<b>Boulder</b>: \uC5C6\uC74C";
|
|
2066
2276
|
}
|
|
2067
2277
|
function createStatusDispatcher(deps) {
|
|
@@ -2162,11 +2372,18 @@ function createStatusDispatcher(deps) {
|
|
|
2162
2372
|
return;
|
|
2163
2373
|
}
|
|
2164
2374
|
const projectRoot = resolveProjectRoot(session);
|
|
2165
|
-
const
|
|
2375
|
+
const rawTitle = session.title ?? entry.title;
|
|
2376
|
+
const rawAgent = entry.agent ?? session.agent;
|
|
2377
|
+
const planReady = await checkPlanReadiness({
|
|
2378
|
+
projectRoot,
|
|
2379
|
+
sessionId: entry.sessionId,
|
|
2380
|
+
planHint: rawTitle,
|
|
2381
|
+
allowLatestFallback: rawAgent === "plan"
|
|
2382
|
+
});
|
|
2166
2383
|
const userSnippet = buildSnippet(findLastByRole(messages, "user"));
|
|
2167
2384
|
const assistantSnippet = buildSnippet(findLastByRole(messages, "assistant"));
|
|
2168
|
-
const title = escapeHtml(
|
|
2169
|
-
const agent =
|
|
2385
|
+
const title = escapeHtml(rawTitle ?? "");
|
|
2386
|
+
const agent = rawAgent ? escapeHtml(rawAgent) : "?";
|
|
2170
2387
|
const text = [
|
|
2171
2388
|
`<b>\uC138\uC158 #${n}</b>: ${title}`,
|
|
2172
2389
|
`\uC5D0\uC774\uC804\uD2B8: ${agent}`,
|
|
@@ -2208,6 +2425,8 @@ function readinessMessage(reason) {
|
|
|
2208
2425
|
return "plan \uC758 \uBAA8\uB4E0 task \uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uC0C8 plan \uC791\uC131 \uD544\uC694";
|
|
2209
2426
|
case "boulder-active":
|
|
2210
2427
|
return ".omo/boulder.json \uC774 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4. \uAE30\uC874 \uC791\uC5C5\uC774 \uC9C4\uD589 \uC911\uC774\uAC70\uB098 archive \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4";
|
|
2428
|
+
case "no-session-plan":
|
|
2429
|
+
return "\uD574\uB2F9 \uC138\uC158\uACFC \uC5F0\uACB0\uB41C plan \uC774 \uC5C6\uC2B5\uB2C8\uB2E4";
|
|
2211
2430
|
}
|
|
2212
2431
|
}
|
|
2213
2432
|
function isSessionNotFoundError(err) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coinseeker/opencode-telegram-plugin",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Control and monitor OpenCode from Telegram with notifications, question replies, and subagent-aware completion.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/telegram-remote.js",
|