agentgram 2.0.0 → 2.0.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.
- package/dist/index.d.ts +72 -27
- package/dist/index.js +1001 -123
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -6,13 +6,8 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
8
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
-
var __esm = (fn, res
|
|
10
|
-
|
|
11
|
-
try {
|
|
12
|
-
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
13
|
-
} catch (e) {
|
|
14
|
-
throw err = [e], e;
|
|
15
|
-
}
|
|
9
|
+
var __esm = (fn, res) => function __init() {
|
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
16
11
|
};
|
|
17
12
|
var __export = (target, all) => {
|
|
18
13
|
for (var name in all)
|
|
@@ -394,12 +389,11 @@ function getGlobalConfigDir() {
|
|
|
394
389
|
return AGENTGRAM_CONFIG_DIR;
|
|
395
390
|
}
|
|
396
391
|
function ensureConfigDirs() {
|
|
397
|
-
const dir = getGlobalConfigDir();
|
|
398
|
-
const stateDir = path2.join(dir, "state");
|
|
399
392
|
try {
|
|
400
393
|
if (!fs2.existsSync(AGENTGRAM_CONFIG_DIR)) fs2.mkdirSync(AGENTGRAM_CONFIG_DIR, { recursive: true, mode: 448 });
|
|
401
|
-
|
|
402
|
-
|
|
394
|
+
const stateDir = path2.join(AGENTGRAM_CONFIG_DIR, "state");
|
|
395
|
+
if (!fs2.existsSync(stateDir)) {
|
|
396
|
+
fs2.mkdirSync(stateDir, { recursive: true, mode: 448 });
|
|
403
397
|
}
|
|
404
398
|
const legacyConfig = path2.join(LEGACY_CONFIG_DIR, "config.json");
|
|
405
399
|
const agentgramConfig = path2.join(AGENTGRAM_CONFIG_DIR, "config.json");
|
|
@@ -477,7 +471,7 @@ var init_config_manager = __esm({
|
|
|
477
471
|
engine: "opencode",
|
|
478
472
|
denyPatterns: [],
|
|
479
473
|
allowedPaths: [],
|
|
480
|
-
workspaces: [resolvedTarget],
|
|
474
|
+
workspaces: resolvedTarget.startsWith(os.tmpdir()) ? [] : [resolvedTarget],
|
|
481
475
|
extra: {}
|
|
482
476
|
};
|
|
483
477
|
this.load();
|
|
@@ -527,13 +521,17 @@ var init_config_manager = __esm({
|
|
|
527
521
|
if (Array.isArray(data.deny_patterns)) this.config.denyPatterns = data.deny_patterns.map(String);
|
|
528
522
|
if (Array.isArray(data.allowed_paths)) this.config.allowedPaths = data.allowed_paths.map(String);
|
|
529
523
|
if (Array.isArray(data.workspaces)) {
|
|
524
|
+
this.config.workspaces = [];
|
|
530
525
|
for (const w of data.workspaces) {
|
|
531
526
|
const resolved = path2.resolve(String(w));
|
|
532
|
-
if (!this.config.workspaces.includes(resolved)) {
|
|
527
|
+
if (fs2.existsSync(resolved) && !resolved.startsWith(os.tmpdir()) && !this.config.workspaces.includes(resolved)) {
|
|
533
528
|
this.config.workspaces.push(resolved);
|
|
534
529
|
}
|
|
535
530
|
}
|
|
536
531
|
}
|
|
532
|
+
if (fs2.existsSync(this.config.targetDir) && !this.config.targetDir.startsWith(os.tmpdir()) && !this.config.workspaces.includes(this.config.targetDir)) {
|
|
533
|
+
this.config.workspaces.unshift(this.config.targetDir);
|
|
534
|
+
}
|
|
537
535
|
}
|
|
538
536
|
saveGlobal() {
|
|
539
537
|
ensureConfigDirs();
|
|
@@ -586,6 +584,16 @@ var init_config_manager = __esm({
|
|
|
586
584
|
}
|
|
587
585
|
return true;
|
|
588
586
|
}
|
|
587
|
+
removeWorkspace(workspace) {
|
|
588
|
+
const resolved = path2.resolve(workspace);
|
|
589
|
+
const idx = this.config.workspaces.indexOf(resolved);
|
|
590
|
+
if (idx !== -1) {
|
|
591
|
+
this.config.workspaces.splice(idx, 1);
|
|
592
|
+
this.saveGlobal();
|
|
593
|
+
return true;
|
|
594
|
+
}
|
|
595
|
+
return false;
|
|
596
|
+
}
|
|
589
597
|
validate() {
|
|
590
598
|
const errors = [];
|
|
591
599
|
const isTelegram = !this.config.channel || this.config.channel === "telegram";
|
|
@@ -605,7 +613,7 @@ var init_config_manager = __esm({
|
|
|
605
613
|
});
|
|
606
614
|
|
|
607
615
|
// src/telegram/telegram-client.ts
|
|
608
|
-
function
|
|
616
|
+
function escapeHtml(text) {
|
|
609
617
|
if (!text) return "";
|
|
610
618
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
611
619
|
}
|
|
@@ -774,8 +782,8 @@ function toTelegramMarkup(keyboard) {
|
|
|
774
782
|
inline_keyboard: keyboard.rows.map(
|
|
775
783
|
(row) => row.map((btn) => ({
|
|
776
784
|
text: btn.text,
|
|
777
|
-
callback_data: btn.callbackData,
|
|
778
|
-
url: btn.url
|
|
785
|
+
callback_data: btn.callbackData ?? void 0,
|
|
786
|
+
url: btn.url ?? void 0
|
|
779
787
|
}))
|
|
780
788
|
)
|
|
781
789
|
};
|
|
@@ -788,8 +796,8 @@ function fromTelegramMarkup(markup) {
|
|
|
788
796
|
rows: markup.inline_keyboard.map(
|
|
789
797
|
(row) => row.map((btn) => ({
|
|
790
798
|
text: btn.text,
|
|
791
|
-
callbackData: btn.callback_data,
|
|
792
|
-
url: btn.url
|
|
799
|
+
callbackData: btn.callback_data ?? void 0,
|
|
800
|
+
url: btn.url ?? void 0
|
|
793
801
|
}))
|
|
794
802
|
)
|
|
795
803
|
};
|
|
@@ -971,7 +979,7 @@ var init_console_adapter = __esm({
|
|
|
971
979
|
timestamp: Date.now()
|
|
972
980
|
};
|
|
973
981
|
}
|
|
974
|
-
async editMessage(
|
|
982
|
+
async editMessage(_recipientId, messageId, text, options) {
|
|
975
983
|
const cleanText = text.replace(/<[^>]+>/g, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
976
984
|
console.log(`
|
|
977
985
|
\x1B[33m[Update #${messageId}]\x1B[0m ${cleanText}`);
|
|
@@ -1240,30 +1248,36 @@ var init_opencode_client = __esm({
|
|
|
1240
1248
|
const actualPort = port > 0 ? port : await getFreePort();
|
|
1241
1249
|
const proc = child_process.spawn(
|
|
1242
1250
|
"opencode",
|
|
1243
|
-
["serve", "--port", String(actualPort), "--hostname", "127.0.0.1"],
|
|
1251
|
+
["serve", "--port", String(actualPort), "--hostname", "127.0.0.1", "--pure"],
|
|
1244
1252
|
{
|
|
1245
1253
|
cwd: targetDir,
|
|
1246
1254
|
env: {
|
|
1247
1255
|
...process.env,
|
|
1248
1256
|
OPENCODE_SERVER_PASSWORD: password
|
|
1249
1257
|
},
|
|
1250
|
-
stdio: ["ignore", "
|
|
1258
|
+
stdio: ["ignore", "ignore", "ignore"]
|
|
1251
1259
|
}
|
|
1252
1260
|
);
|
|
1253
1261
|
const client = new _OpenCodeClient(`http://127.0.0.1:${actualPort}`, password, targetDir);
|
|
1254
1262
|
let ready = false;
|
|
1255
|
-
for (let i = 0; i <
|
|
1263
|
+
for (let i = 0; i < 60; i++) {
|
|
1264
|
+
if (proc.exitCode !== null) {
|
|
1265
|
+
throw new Error(`OpenCode process exited early with code ${proc.exitCode}`);
|
|
1266
|
+
}
|
|
1256
1267
|
try {
|
|
1257
1268
|
await client.request("GET", "/global/health");
|
|
1258
1269
|
ready = true;
|
|
1259
1270
|
break;
|
|
1260
1271
|
} catch {
|
|
1261
|
-
await new Promise((r) => setTimeout(r,
|
|
1272
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
1262
1273
|
}
|
|
1263
1274
|
}
|
|
1264
1275
|
if (!ready) {
|
|
1265
|
-
|
|
1266
|
-
|
|
1276
|
+
try {
|
|
1277
|
+
proc.kill("SIGTERM");
|
|
1278
|
+
} catch {
|
|
1279
|
+
}
|
|
1280
|
+
throw new Error(`OpenCode server failed to start on port ${actualPort} within 60s`);
|
|
1267
1281
|
}
|
|
1268
1282
|
client.serverProcess = proc;
|
|
1269
1283
|
return { client, proc, port: actualPort };
|
|
@@ -1342,6 +1356,12 @@ var init_opencode_adapter = __esm({
|
|
|
1342
1356
|
this.client.on("event", this.boundEventHandler);
|
|
1343
1357
|
this.client.connectEventStream();
|
|
1344
1358
|
}
|
|
1359
|
+
async listModels() {
|
|
1360
|
+
return this.client.listModels();
|
|
1361
|
+
}
|
|
1362
|
+
async listAgents() {
|
|
1363
|
+
return this.client.listAgents();
|
|
1364
|
+
}
|
|
1345
1365
|
};
|
|
1346
1366
|
}
|
|
1347
1367
|
});
|
|
@@ -1567,6 +1587,10 @@ var init_i18n = __esm({
|
|
|
1567
1587
|
btn_handoff: "\u{1F501} Handoff",
|
|
1568
1588
|
btn_help: "\u2753 Help",
|
|
1569
1589
|
btn_language: "\u{1F310} Language",
|
|
1590
|
+
btn_back: "\u2B05\uFE0F Back",
|
|
1591
|
+
btn_all_models: "\u27A1\uFE0F All Models",
|
|
1592
|
+
btn_favorites: "\u2B50 Favorites",
|
|
1593
|
+
btn_next: "\u27A1\uFE0F Next",
|
|
1570
1594
|
// Permission Buttons
|
|
1571
1595
|
perm_allow_once: "\u2705 Allow Once",
|
|
1572
1596
|
perm_always_allow: "\u267E\uFE0F Always Allow",
|
|
@@ -1612,6 +1636,10 @@ var init_i18n = __esm({
|
|
|
1612
1636
|
btn_handoff: "\u{1F501} \u062A\u0633\u0644\u064A\u0645",
|
|
1613
1637
|
btn_help: "\u2753 \u0645\u0633\u0627\u0639\u062F\u0629",
|
|
1614
1638
|
btn_language: "\u{1F310} \u0627\u0644\u0644\u063A\u0629",
|
|
1639
|
+
btn_back: "\u2B05\uFE0F \u0631\u062C\u0648\u0639",
|
|
1640
|
+
btn_all_models: "\u27A1\uFE0F \u0627\u0644\u0645\u0632\u064A\u062F",
|
|
1641
|
+
btn_favorites: "\u2B50 \u0627\u0644\u0645\u0641\u0636\u0644\u0629",
|
|
1642
|
+
btn_next: "\u27A1\uFE0F \u0627\u0644\u062A\u0627\u0644\u064A",
|
|
1615
1643
|
// Permission Buttons
|
|
1616
1644
|
perm_allow_once: "\u2705 \u0645\u0631\u0629 \u0648\u0627\u062D\u062F\u0629",
|
|
1617
1645
|
perm_always_allow: "\u267E\uFE0F \u0633\u0645\u0627\u062D \u062F\u0627\u0626\u0645\u0627\u064B",
|
|
@@ -1645,6 +1673,315 @@ var init_i18n = __esm({
|
|
|
1645
1673
|
}
|
|
1646
1674
|
});
|
|
1647
1675
|
|
|
1676
|
+
// src/domain/model-catalog.ts
|
|
1677
|
+
function formatModelName(modelId) {
|
|
1678
|
+
const parts = modelId.split("/");
|
|
1679
|
+
const base = parts[parts.length - 1] || modelId;
|
|
1680
|
+
return base.replace(/-free$/i, "").split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
1681
|
+
}
|
|
1682
|
+
function resolveModelMetadata(modelId) {
|
|
1683
|
+
if (!modelId) {
|
|
1684
|
+
return {
|
|
1685
|
+
id: "default",
|
|
1686
|
+
name: "Default Model",
|
|
1687
|
+
provider: "Default",
|
|
1688
|
+
contextWindow: "128k",
|
|
1689
|
+
tag: "Default Engine Model"
|
|
1690
|
+
};
|
|
1691
|
+
}
|
|
1692
|
+
if (KNOWN_MODELS[modelId]) {
|
|
1693
|
+
return KNOWN_MODELS[modelId];
|
|
1694
|
+
}
|
|
1695
|
+
const lower = modelId.toLowerCase();
|
|
1696
|
+
for (const [key, meta] of Object.entries(KNOWN_MODELS)) {
|
|
1697
|
+
if (lower === key.toLowerCase() || lower.endsWith(`/${key.toLowerCase()}`)) {
|
|
1698
|
+
return { ...meta, id: modelId };
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
if (lower.includes("gemini-1.5-pro") || lower.includes("gemini-2.0-pro")) {
|
|
1702
|
+
return {
|
|
1703
|
+
id: modelId,
|
|
1704
|
+
name: formatModelName(modelId),
|
|
1705
|
+
provider: "Google",
|
|
1706
|
+
contextWindow: "2M",
|
|
1707
|
+
tag: "Ultra-Long Context (2M)",
|
|
1708
|
+
tier: "flagship"
|
|
1709
|
+
};
|
|
1710
|
+
}
|
|
1711
|
+
if (lower.includes("gemini")) {
|
|
1712
|
+
return {
|
|
1713
|
+
id: modelId,
|
|
1714
|
+
name: formatModelName(modelId),
|
|
1715
|
+
provider: "Google",
|
|
1716
|
+
contextWindow: "1M",
|
|
1717
|
+
tag: "1M Tokens Multimodal",
|
|
1718
|
+
tier: "standard"
|
|
1719
|
+
};
|
|
1720
|
+
}
|
|
1721
|
+
if (lower.includes("claude-3-5") || lower.includes("sonnet") || lower.includes("haiku") || lower.includes("opus")) {
|
|
1722
|
+
return {
|
|
1723
|
+
id: modelId,
|
|
1724
|
+
name: formatModelName(modelId),
|
|
1725
|
+
provider: "Anthropic",
|
|
1726
|
+
contextWindow: "200k",
|
|
1727
|
+
tag: "SOTA Coding & Tool Use",
|
|
1728
|
+
tier: "flagship"
|
|
1729
|
+
};
|
|
1730
|
+
}
|
|
1731
|
+
if (lower.includes("deepseek-r1") || lower.includes("reasoner")) {
|
|
1732
|
+
return {
|
|
1733
|
+
id: modelId,
|
|
1734
|
+
name: formatModelName(modelId),
|
|
1735
|
+
provider: "DeepSeek",
|
|
1736
|
+
contextWindow: "128k",
|
|
1737
|
+
tag: "Deep Reasoning CoT",
|
|
1738
|
+
tier: "flagship"
|
|
1739
|
+
};
|
|
1740
|
+
}
|
|
1741
|
+
if (lower.includes("deepseek")) {
|
|
1742
|
+
return {
|
|
1743
|
+
id: modelId,
|
|
1744
|
+
name: formatModelName(modelId),
|
|
1745
|
+
provider: "DeepSeek",
|
|
1746
|
+
contextWindow: "128k",
|
|
1747
|
+
tag: "High-Speed Coding & Logic",
|
|
1748
|
+
tier: "flagship"
|
|
1749
|
+
};
|
|
1750
|
+
}
|
|
1751
|
+
if (lower.includes("o3")) {
|
|
1752
|
+
return {
|
|
1753
|
+
id: modelId,
|
|
1754
|
+
name: formatModelName(modelId),
|
|
1755
|
+
provider: "OpenAI",
|
|
1756
|
+
contextWindow: "200k",
|
|
1757
|
+
tag: "Advanced Math & Code",
|
|
1758
|
+
tier: "flagship"
|
|
1759
|
+
};
|
|
1760
|
+
}
|
|
1761
|
+
if (lower.includes("o1") || lower.includes("gpt-4")) {
|
|
1762
|
+
return {
|
|
1763
|
+
id: modelId,
|
|
1764
|
+
name: formatModelName(modelId),
|
|
1765
|
+
provider: "OpenAI",
|
|
1766
|
+
contextWindow: "128k",
|
|
1767
|
+
tag: "Omni Reasoning & Logic",
|
|
1768
|
+
tier: "flagship"
|
|
1769
|
+
};
|
|
1770
|
+
}
|
|
1771
|
+
if (lower.includes("qwen") || lower.includes("llama") || lower.includes("mistral")) {
|
|
1772
|
+
return {
|
|
1773
|
+
id: modelId,
|
|
1774
|
+
name: formatModelName(modelId),
|
|
1775
|
+
provider: "Open Weights",
|
|
1776
|
+
contextWindow: "128k",
|
|
1777
|
+
tag: "Open-Source Architecture",
|
|
1778
|
+
tier: "standard"
|
|
1779
|
+
};
|
|
1780
|
+
}
|
|
1781
|
+
if (lower.includes("free") || lower.includes("space-bunny") || lower.includes("longcat") || lower.includes("mimo")) {
|
|
1782
|
+
return {
|
|
1783
|
+
id: modelId,
|
|
1784
|
+
name: formatModelName(modelId),
|
|
1785
|
+
provider: "OpenCode Free",
|
|
1786
|
+
contextWindow: "128k",
|
|
1787
|
+
tag: "Community Free Model",
|
|
1788
|
+
tier: "free"
|
|
1789
|
+
};
|
|
1790
|
+
}
|
|
1791
|
+
return {
|
|
1792
|
+
id: modelId,
|
|
1793
|
+
name: formatModelName(modelId),
|
|
1794
|
+
provider: "AI Provider",
|
|
1795
|
+
contextWindow: "128k",
|
|
1796
|
+
tag: "General Intelligence"
|
|
1797
|
+
};
|
|
1798
|
+
}
|
|
1799
|
+
function getStandardModelCatalog() {
|
|
1800
|
+
return Object.keys(KNOWN_MODELS);
|
|
1801
|
+
}
|
|
1802
|
+
var KNOWN_MODELS;
|
|
1803
|
+
var init_model_catalog = __esm({
|
|
1804
|
+
"src/domain/model-catalog.ts"() {
|
|
1805
|
+
"use strict";
|
|
1806
|
+
KNOWN_MODELS = {
|
|
1807
|
+
// Anthropic
|
|
1808
|
+
"claude-3-5-sonnet-20241022": {
|
|
1809
|
+
id: "claude-3-5-sonnet-20241022",
|
|
1810
|
+
name: "Claude 3.5 Sonnet (v2)",
|
|
1811
|
+
provider: "Anthropic",
|
|
1812
|
+
contextWindow: "200k",
|
|
1813
|
+
tag: "Coding Champion & Tool Use",
|
|
1814
|
+
tier: "flagship"
|
|
1815
|
+
},
|
|
1816
|
+
"claude-3-5-sonnet": {
|
|
1817
|
+
id: "claude-3-5-sonnet",
|
|
1818
|
+
name: "Claude 3.5 Sonnet",
|
|
1819
|
+
provider: "Anthropic",
|
|
1820
|
+
contextWindow: "200k",
|
|
1821
|
+
tag: "Coding & Agentic Automation",
|
|
1822
|
+
tier: "flagship"
|
|
1823
|
+
},
|
|
1824
|
+
"claude-3-5-haiku": {
|
|
1825
|
+
id: "claude-3-5-haiku",
|
|
1826
|
+
name: "Claude 3.5 Haiku",
|
|
1827
|
+
provider: "Anthropic",
|
|
1828
|
+
contextWindow: "200k",
|
|
1829
|
+
tag: "Ultra-Fast & Smart",
|
|
1830
|
+
tier: "standard"
|
|
1831
|
+
},
|
|
1832
|
+
"claude-3-opus": {
|
|
1833
|
+
id: "claude-3-opus",
|
|
1834
|
+
name: "Claude 3 Opus",
|
|
1835
|
+
provider: "Anthropic",
|
|
1836
|
+
contextWindow: "200k",
|
|
1837
|
+
tag: "Deep Reasoning & Synthesis",
|
|
1838
|
+
tier: "flagship"
|
|
1839
|
+
},
|
|
1840
|
+
// OpenAI
|
|
1841
|
+
"gpt-4o": {
|
|
1842
|
+
id: "gpt-4o",
|
|
1843
|
+
name: "GPT-4o (Omni)",
|
|
1844
|
+
provider: "OpenAI",
|
|
1845
|
+
contextWindow: "128k",
|
|
1846
|
+
tag: "Multimodal Flagship",
|
|
1847
|
+
tier: "flagship"
|
|
1848
|
+
},
|
|
1849
|
+
"gpt-4o-mini": {
|
|
1850
|
+
id: "gpt-4o-mini",
|
|
1851
|
+
name: "GPT-4o Mini",
|
|
1852
|
+
provider: "OpenAI",
|
|
1853
|
+
contextWindow: "128k",
|
|
1854
|
+
tag: "High Speed & Efficiency",
|
|
1855
|
+
tier: "standard"
|
|
1856
|
+
},
|
|
1857
|
+
"o1": {
|
|
1858
|
+
id: "o1",
|
|
1859
|
+
name: "OpenAI o1",
|
|
1860
|
+
provider: "OpenAI",
|
|
1861
|
+
contextWindow: "128k",
|
|
1862
|
+
tag: "Deep CoT Reflection & Logic",
|
|
1863
|
+
tier: "flagship"
|
|
1864
|
+
},
|
|
1865
|
+
"o1-mini": {
|
|
1866
|
+
id: "o1-mini",
|
|
1867
|
+
name: "OpenAI o1-mini",
|
|
1868
|
+
provider: "OpenAI",
|
|
1869
|
+
contextWindow: "128k",
|
|
1870
|
+
tag: "Math & STEM Reasoning",
|
|
1871
|
+
tier: "standard"
|
|
1872
|
+
},
|
|
1873
|
+
"o3-mini": {
|
|
1874
|
+
id: "o3-mini",
|
|
1875
|
+
name: "OpenAI o3-mini",
|
|
1876
|
+
provider: "OpenAI",
|
|
1877
|
+
contextWindow: "200k",
|
|
1878
|
+
tag: "High-Performance Math & Code",
|
|
1879
|
+
tier: "flagship"
|
|
1880
|
+
},
|
|
1881
|
+
// Google Gemini
|
|
1882
|
+
"gemini-1.5-pro": {
|
|
1883
|
+
id: "gemini-1.5-pro",
|
|
1884
|
+
name: "Gemini 1.5 Pro",
|
|
1885
|
+
provider: "Google",
|
|
1886
|
+
contextWindow: "2M",
|
|
1887
|
+
tag: "Massive 2M Tokens Repo Context",
|
|
1888
|
+
tier: "flagship"
|
|
1889
|
+
},
|
|
1890
|
+
"gemini-1.5-flash": {
|
|
1891
|
+
id: "gemini-1.5-flash",
|
|
1892
|
+
name: "Gemini 1.5 Flash",
|
|
1893
|
+
provider: "Google",
|
|
1894
|
+
contextWindow: "1M",
|
|
1895
|
+
tag: "Fast 1M Window & Multimodal",
|
|
1896
|
+
tier: "standard"
|
|
1897
|
+
},
|
|
1898
|
+
"gemini-2.0-flash": {
|
|
1899
|
+
id: "gemini-2.0-flash",
|
|
1900
|
+
name: "Gemini 2.0 Flash",
|
|
1901
|
+
provider: "Google",
|
|
1902
|
+
contextWindow: "1M",
|
|
1903
|
+
tag: "Next-Gen Realtime Multimodal",
|
|
1904
|
+
tier: "flagship"
|
|
1905
|
+
},
|
|
1906
|
+
// DeepSeek
|
|
1907
|
+
"deepseek-chat": {
|
|
1908
|
+
id: "deepseek-chat",
|
|
1909
|
+
name: "DeepSeek V3",
|
|
1910
|
+
provider: "DeepSeek",
|
|
1911
|
+
contextWindow: "128k",
|
|
1912
|
+
tag: "SOTA Coding & Architecture",
|
|
1913
|
+
tier: "flagship"
|
|
1914
|
+
},
|
|
1915
|
+
"deepseek-reasoner": {
|
|
1916
|
+
id: "deepseek-reasoner",
|
|
1917
|
+
name: "DeepSeek R1",
|
|
1918
|
+
provider: "DeepSeek",
|
|
1919
|
+
contextWindow: "128k",
|
|
1920
|
+
tag: "Open CoT Reasoning Engine",
|
|
1921
|
+
tier: "flagship"
|
|
1922
|
+
},
|
|
1923
|
+
// OpenCode Community Free Models
|
|
1924
|
+
"opencode/deepseek-v4.1-flash-free": {
|
|
1925
|
+
id: "opencode/deepseek-v4.1-flash-free",
|
|
1926
|
+
name: "DeepSeek v4.1 Flash",
|
|
1927
|
+
provider: "OpenCode Free",
|
|
1928
|
+
contextWindow: "128k",
|
|
1929
|
+
tag: "Fast Free Coding Agent",
|
|
1930
|
+
tier: "free"
|
|
1931
|
+
},
|
|
1932
|
+
"opencode/space-bunny-free": {
|
|
1933
|
+
id: "opencode/space-bunny-free",
|
|
1934
|
+
name: "Space Bunny Free",
|
|
1935
|
+
provider: "OpenCode Free",
|
|
1936
|
+
contextWindow: "128k",
|
|
1937
|
+
tag: "Community Automation Agent",
|
|
1938
|
+
tier: "free"
|
|
1939
|
+
},
|
|
1940
|
+
"opencode/glm-5.3-flash-free": {
|
|
1941
|
+
id: "opencode/glm-5.3-flash-free",
|
|
1942
|
+
name: "GLM 5.3 Flash Free",
|
|
1943
|
+
provider: "OpenCode Free",
|
|
1944
|
+
contextWindow: "128k",
|
|
1945
|
+
tag: "High Concurrency Coding",
|
|
1946
|
+
tier: "free"
|
|
1947
|
+
},
|
|
1948
|
+
"opencode/nemotron-3-ultra-free": {
|
|
1949
|
+
id: "opencode/nemotron-3-ultra-free",
|
|
1950
|
+
name: "Nemotron 3 Ultra Free",
|
|
1951
|
+
provider: "OpenCode Free",
|
|
1952
|
+
contextWindow: "128k",
|
|
1953
|
+
tag: "NVIDIA Hardware Accelerated",
|
|
1954
|
+
tier: "free"
|
|
1955
|
+
},
|
|
1956
|
+
"opencode/mimo-v2.6-flash-free": {
|
|
1957
|
+
id: "opencode/mimo-v2.6-flash-free",
|
|
1958
|
+
name: "Mimo v2.6 Flash Free",
|
|
1959
|
+
provider: "OpenCode Free",
|
|
1960
|
+
contextWindow: "128k",
|
|
1961
|
+
tag: "Lightweight Quick Edits",
|
|
1962
|
+
tier: "free"
|
|
1963
|
+
},
|
|
1964
|
+
"opencode/longcat-2.5-preview-free": {
|
|
1965
|
+
id: "opencode/longcat-2.5-preview-free",
|
|
1966
|
+
name: "LongCat 2.5 Preview",
|
|
1967
|
+
provider: "OpenCode Free",
|
|
1968
|
+
contextWindow: "128k",
|
|
1969
|
+
tag: "Long Context Free Preview",
|
|
1970
|
+
tier: "free"
|
|
1971
|
+
},
|
|
1972
|
+
// Open Weights
|
|
1973
|
+
"qwen2.5-coder-32b": {
|
|
1974
|
+
id: "qwen2.5-coder-32b",
|
|
1975
|
+
name: "Qwen 2.5 Coder 32B",
|
|
1976
|
+
provider: "Alibaba",
|
|
1977
|
+
contextWindow: "128k",
|
|
1978
|
+
tag: "Open-Weights Coding Champion",
|
|
1979
|
+
tier: "flagship"
|
|
1980
|
+
}
|
|
1981
|
+
};
|
|
1982
|
+
}
|
|
1983
|
+
});
|
|
1984
|
+
|
|
1648
1985
|
// src/control-room/control-room.ts
|
|
1649
1986
|
function parseCallback(data) {
|
|
1650
1987
|
if (data.startsWith("pm:")) {
|
|
@@ -1699,18 +2036,21 @@ function permissionKeyboard(permId, lang = "en") {
|
|
|
1699
2036
|
inline_keyboard: rows
|
|
1700
2037
|
};
|
|
1701
2038
|
}
|
|
1702
|
-
var fs3, path3, SYSTEM_HEADER, ControlRoom;
|
|
2039
|
+
var fs3, os2, path3, child_process3, SYSTEM_HEADER, ControlRoom;
|
|
1703
2040
|
var init_control_room = __esm({
|
|
1704
2041
|
"src/control-room/control-room.ts"() {
|
|
1705
2042
|
"use strict";
|
|
1706
2043
|
fs3 = __toESM(require("fs"));
|
|
2044
|
+
os2 = __toESM(require("os"));
|
|
1707
2045
|
path3 = __toESM(require("path"));
|
|
2046
|
+
child_process3 = __toESM(require("child_process"));
|
|
1708
2047
|
init_telegram_client();
|
|
1709
2048
|
init_opencode_client();
|
|
1710
2049
|
init_telegram_adapter();
|
|
1711
2050
|
init_opencode_adapter();
|
|
1712
2051
|
init_policy();
|
|
1713
2052
|
init_i18n();
|
|
2053
|
+
init_model_catalog();
|
|
1714
2054
|
SYSTEM_HEADER = (targetDir) => `
|
|
1715
2055
|
BRIDGE RULES (highest priority):
|
|
1716
2056
|
- Primary project workspace: ${targetDir}.
|
|
@@ -1736,6 +2076,7 @@ BRIDGE RULES (highest priority):
|
|
|
1736
2076
|
alwaysAllowedPerms = /* @__PURE__ */ new Set();
|
|
1737
2077
|
missionCardMsgId = null;
|
|
1738
2078
|
updateTimer = null;
|
|
2079
|
+
activeSkill = null;
|
|
1739
2080
|
isListening = false;
|
|
1740
2081
|
constructor(arg1, arg2, arg3) {
|
|
1741
2082
|
if ("channel" in arg1 && "engine" in arg1) {
|
|
@@ -1786,13 +2127,23 @@ BRIDGE RULES (highest priority):
|
|
|
1786
2127
|
});
|
|
1787
2128
|
}
|
|
1788
2129
|
async start() {
|
|
1789
|
-
|
|
2130
|
+
try {
|
|
2131
|
+
await this.engine.connect();
|
|
2132
|
+
} catch (err) {
|
|
2133
|
+
console.warn("\u26A0\uFE0F Warning: Engine connection failed at startup:", err.message);
|
|
2134
|
+
}
|
|
1790
2135
|
this.isListening = true;
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
2136
|
+
if (this.allowedChatId && this.allowedChatId.trim()) {
|
|
2137
|
+
try {
|
|
2138
|
+
await this.channel.sendMessage(
|
|
2139
|
+
this.allowedChatId,
|
|
2140
|
+
t("welcome", this.language, { target: escapeHtml(this.targetDir) }),
|
|
2141
|
+
{ replyMarkup: this.getMainKeyboard() }
|
|
2142
|
+
);
|
|
2143
|
+
} catch (err) {
|
|
2144
|
+
console.warn("\u26A0\uFE0F Warning: Could not deliver initial welcome card:", err.message);
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
1796
2147
|
await this.channel.startListening({
|
|
1797
2148
|
onMessage: async (msg) => {
|
|
1798
2149
|
if (this.channel.id === "telegram" && this.allowedChatId && msg.chatId !== this.allowedChatId) {
|
|
@@ -1826,20 +2177,57 @@ BRIDGE RULES (highest priority):
|
|
|
1826
2177
|
if (text === "/start" || text === "/help") {
|
|
1827
2178
|
await this.channel.sendMessage(
|
|
1828
2179
|
this.allowedChatId,
|
|
1829
|
-
`\u26A1 <b>AgentGram v2.0.0</b>
|
|
2180
|
+
`\u26A1 <b>AgentGram v2.0.0 \xB7 Mission Control</b>
|
|
1830
2181
|
${t("help_title", this.language)}`,
|
|
1831
2182
|
{ replyMarkup: this.getMainKeyboard() }
|
|
1832
2183
|
);
|
|
1833
2184
|
return;
|
|
1834
2185
|
}
|
|
2186
|
+
if (text === "/status" || text === "st") {
|
|
2187
|
+
await this.sendStatusReport();
|
|
2188
|
+
return;
|
|
2189
|
+
}
|
|
2190
|
+
if (text === "/agents") {
|
|
2191
|
+
await this.sendAgentsMenu();
|
|
2192
|
+
return;
|
|
2193
|
+
}
|
|
2194
|
+
if (text === "/models") {
|
|
2195
|
+
await this.sendModelsMenu();
|
|
2196
|
+
return;
|
|
2197
|
+
}
|
|
1835
2198
|
if (text === "/mode") {
|
|
1836
2199
|
await this.sendModeMenu();
|
|
1837
2200
|
return;
|
|
1838
2201
|
}
|
|
2202
|
+
if (text === "/sessions") {
|
|
2203
|
+
await this.sendSessionsMenu();
|
|
2204
|
+
return;
|
|
2205
|
+
}
|
|
2206
|
+
if (text === "/new") {
|
|
2207
|
+
this.activeRun = null;
|
|
2208
|
+
await this.channel.sendMessage(
|
|
2209
|
+
this.allowedChatId,
|
|
2210
|
+
"\u2728 <b>New Session Ready</b> \u2014 send your prompt to start.",
|
|
2211
|
+
{ replyMarkup: this.getMainKeyboard() }
|
|
2212
|
+
);
|
|
2213
|
+
return;
|
|
2214
|
+
}
|
|
1839
2215
|
if (text === "/diff") {
|
|
1840
2216
|
await this.sendDiff();
|
|
1841
2217
|
return;
|
|
1842
2218
|
}
|
|
2219
|
+
if (text === "/skills") {
|
|
2220
|
+
await this.sendSkillsMenu();
|
|
2221
|
+
return;
|
|
2222
|
+
}
|
|
2223
|
+
if (text === "/usage") {
|
|
2224
|
+
await this.sendUsageReport();
|
|
2225
|
+
return;
|
|
2226
|
+
}
|
|
2227
|
+
if (text === "/handoff") {
|
|
2228
|
+
await this.sendHandoffReport();
|
|
2229
|
+
return;
|
|
2230
|
+
}
|
|
1843
2231
|
if (text === "/stop") {
|
|
1844
2232
|
await this.abortCurrentRun();
|
|
1845
2233
|
return;
|
|
@@ -1865,7 +2253,7 @@ ${t("help_title", this.language)}`,
|
|
|
1865
2253
|
if (hits.length > 0) {
|
|
1866
2254
|
await this.channel.sendMessage(
|
|
1867
2255
|
this.allowedChatId,
|
|
1868
|
-
t("policy_denied", this.language, { hits:
|
|
2256
|
+
t("policy_denied", this.language, { hits: escapeHtml(hits.slice(0, 3).join(", ")) })
|
|
1869
2257
|
);
|
|
1870
2258
|
return;
|
|
1871
2259
|
}
|
|
@@ -1874,7 +2262,7 @@ ${t("help_title", this.language)}`,
|
|
|
1874
2262
|
await this.channel.sendMessage(
|
|
1875
2263
|
this.allowedChatId,
|
|
1876
2264
|
t("prompt_injection_blocked", this.language, {
|
|
1877
|
-
reason:
|
|
2265
|
+
reason: escapeHtml(detection.reason),
|
|
1878
2266
|
confidence: Math.round(detection.confidence * 100)
|
|
1879
2267
|
})
|
|
1880
2268
|
);
|
|
@@ -1915,12 +2303,18 @@ ${t("help_title", this.language)}`,
|
|
|
1915
2303
|
);
|
|
1916
2304
|
this.missionCardMsgId = cardMsg.messageId;
|
|
1917
2305
|
this.startMissionCardTicker();
|
|
1918
|
-
|
|
2306
|
+
let finalPrompt = promptText;
|
|
2307
|
+
if (this.activeSkill) {
|
|
2308
|
+
finalPrompt = `[Active Skill: ${this.activeSkill}]
|
|
2309
|
+
${promptText}`;
|
|
2310
|
+
this.activeSkill = null;
|
|
2311
|
+
}
|
|
2312
|
+
const sanitized = this.policy.sanitizePrompt(finalPrompt);
|
|
1919
2313
|
await this.engine.submitPrompt(sessionId, sanitized, this.currentAgent, this.currentModel);
|
|
1920
2314
|
} catch (err) {
|
|
1921
2315
|
await this.channel.sendMessage(
|
|
1922
2316
|
this.allowedChatId,
|
|
1923
|
-
`\u274C Error: ${
|
|
2317
|
+
`\u274C Error: ${escapeHtml(err.message)}`
|
|
1924
2318
|
);
|
|
1925
2319
|
}
|
|
1926
2320
|
}
|
|
@@ -1951,29 +2345,108 @@ ${t("help_title", this.language)}`,
|
|
|
1951
2345
|
}
|
|
1952
2346
|
return;
|
|
1953
2347
|
}
|
|
2348
|
+
if (data === "menu:home" || data === "home") {
|
|
2349
|
+
await this.channel.sendMessage(
|
|
2350
|
+
this.allowedChatId,
|
|
2351
|
+
t("welcome", this.language, { target: escapeHtml(this.targetDir) }),
|
|
2352
|
+
{ replyMarkup: this.getMainKeyboard() }
|
|
2353
|
+
);
|
|
2354
|
+
return;
|
|
2355
|
+
}
|
|
2356
|
+
if (data === "menu:ag") {
|
|
2357
|
+
await this.sendAgentsMenu();
|
|
2358
|
+
return;
|
|
2359
|
+
}
|
|
2360
|
+
if (data.startsWith("ag:")) {
|
|
2361
|
+
const agent = data.slice(3);
|
|
2362
|
+
this.currentAgent = agent;
|
|
2363
|
+
this.cfgManager.config.defaultAgent = agent;
|
|
2364
|
+
this.cfgManager.saveGlobal();
|
|
2365
|
+
await this.channel.sendMessage(
|
|
2366
|
+
this.allowedChatId,
|
|
2367
|
+
`\u{1F9E0} Agent changed to: <b>${escapeHtml(agent)}</b>`,
|
|
2368
|
+
{ replyMarkup: this.getMainKeyboard() }
|
|
2369
|
+
);
|
|
2370
|
+
return;
|
|
2371
|
+
}
|
|
2372
|
+
if (data === "menu:md") {
|
|
2373
|
+
await this.sendModelsMenu(0);
|
|
2374
|
+
return;
|
|
2375
|
+
}
|
|
2376
|
+
if (data.startsWith("pg:")) {
|
|
2377
|
+
const page = parseInt(data.slice(3), 10) || 0;
|
|
2378
|
+
await this.sendModelsMenu(page);
|
|
2379
|
+
return;
|
|
2380
|
+
}
|
|
2381
|
+
if (data.startsWith("md:raw:")) {
|
|
2382
|
+
const model = data.slice(7);
|
|
2383
|
+
if (model) {
|
|
2384
|
+
this.currentModel = model;
|
|
2385
|
+
this.cfgManager.config.defaultModel = model;
|
|
2386
|
+
this.cfgManager.saveGlobal();
|
|
2387
|
+
await this.channel.sendMessage(
|
|
2388
|
+
this.allowedChatId,
|
|
2389
|
+
`\u{1F916} Model changed to: <b>${escapeHtml(model)}</b>`,
|
|
2390
|
+
{ replyMarkup: this.getMainKeyboard() }
|
|
2391
|
+
);
|
|
2392
|
+
}
|
|
2393
|
+
return;
|
|
2394
|
+
}
|
|
2395
|
+
if (data.startsWith("md:")) {
|
|
2396
|
+
const idx = parseInt(data.slice(3), 10);
|
|
2397
|
+
const model = this.cfgManager.config.favoriteModels[idx];
|
|
2398
|
+
if (model) {
|
|
2399
|
+
this.currentModel = model;
|
|
2400
|
+
this.cfgManager.config.defaultModel = model;
|
|
2401
|
+
this.cfgManager.saveGlobal();
|
|
2402
|
+
await this.channel.sendMessage(
|
|
2403
|
+
this.allowedChatId,
|
|
2404
|
+
`\u{1F916} Model changed to: <b>${escapeHtml(model)}</b>`,
|
|
2405
|
+
{ replyMarkup: this.getMainKeyboard() }
|
|
2406
|
+
);
|
|
2407
|
+
}
|
|
2408
|
+
return;
|
|
2409
|
+
}
|
|
2410
|
+
if (data === "menu:mo") {
|
|
2411
|
+
await this.sendModeMenu();
|
|
2412
|
+
return;
|
|
2413
|
+
}
|
|
1954
2414
|
if (data.startsWith("mo:")) {
|
|
1955
2415
|
const mode = data.slice(3);
|
|
1956
2416
|
if (["read", "build", "auto"].includes(mode)) {
|
|
1957
2417
|
this.currentMode = mode;
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
}
|
|
2418
|
+
await this.channel.sendMessage(
|
|
2419
|
+
this.allowedChatId,
|
|
2420
|
+
`\u{1F512} Mode changed to: <b>${mode}</b>`,
|
|
2421
|
+
{ replyMarkup: this.getMainKeyboard() }
|
|
2422
|
+
);
|
|
1964
2423
|
}
|
|
1965
2424
|
return;
|
|
1966
2425
|
}
|
|
1967
|
-
if (data === "
|
|
1968
|
-
await this.
|
|
2426
|
+
if (data === "menu:se") {
|
|
2427
|
+
await this.sendSessionsMenu();
|
|
1969
2428
|
return;
|
|
1970
2429
|
}
|
|
1971
|
-
if (data === "
|
|
1972
|
-
|
|
2430
|
+
if (data === "new") {
|
|
2431
|
+
this.activeRun = null;
|
|
2432
|
+
await this.channel.sendMessage(
|
|
2433
|
+
this.allowedChatId,
|
|
2434
|
+
"\u2728 <b>New Session Ready</b> \u2014 send your prompt to start fresh.",
|
|
2435
|
+
{ replyMarkup: this.getMainKeyboard() }
|
|
2436
|
+
);
|
|
1973
2437
|
return;
|
|
1974
2438
|
}
|
|
1975
|
-
if (data
|
|
1976
|
-
|
|
2439
|
+
if (data.startsWith("se:")) {
|
|
2440
|
+
const sid = data.slice(3);
|
|
2441
|
+
await this.channel.sendMessage(
|
|
2442
|
+
this.allowedChatId,
|
|
2443
|
+
`\u{1F4C2} Resumed session: <code>${escapeHtml(sid)}</code>`,
|
|
2444
|
+
{ replyMarkup: this.getMainKeyboard() }
|
|
2445
|
+
);
|
|
2446
|
+
return;
|
|
2447
|
+
}
|
|
2448
|
+
if (data === "st") {
|
|
2449
|
+
await this.sendStatusReport();
|
|
1977
2450
|
return;
|
|
1978
2451
|
}
|
|
1979
2452
|
if (data === "menu:ws") {
|
|
@@ -1987,6 +2460,69 @@ ${t("help_title", this.language)}`,
|
|
|
1987
2460
|
if (target) {
|
|
1988
2461
|
await this.switchWorkspace(target);
|
|
1989
2462
|
}
|
|
2463
|
+
return;
|
|
2464
|
+
}
|
|
2465
|
+
if (data === "diff") {
|
|
2466
|
+
await this.sendDiff();
|
|
2467
|
+
return;
|
|
2468
|
+
}
|
|
2469
|
+
if (data === "menu:sk") {
|
|
2470
|
+
await this.sendSkillsMenu(0);
|
|
2471
|
+
return;
|
|
2472
|
+
}
|
|
2473
|
+
if (data.startsWith("skpage:")) {
|
|
2474
|
+
const page = parseInt(data.slice(7), 10) || 0;
|
|
2475
|
+
await this.sendSkillsMenu(page);
|
|
2476
|
+
return;
|
|
2477
|
+
}
|
|
2478
|
+
if (data.startsWith("sk:")) {
|
|
2479
|
+
const sk = data.slice(3);
|
|
2480
|
+
this.activeSkill = sk;
|
|
2481
|
+
await this.channel.sendMessage(
|
|
2482
|
+
this.allowedChatId,
|
|
2483
|
+
`\u{1F9F0} Selected Skill: <b>${escapeHtml(sk)}</b> \u2014 send your task to execute with this skill.`,
|
|
2484
|
+
{ replyMarkup: this.getMainKeyboard() }
|
|
2485
|
+
);
|
|
2486
|
+
return;
|
|
2487
|
+
}
|
|
2488
|
+
if (data === "us") {
|
|
2489
|
+
await this.sendUsageReport();
|
|
2490
|
+
return;
|
|
2491
|
+
}
|
|
2492
|
+
if (data === "menu:lg") {
|
|
2493
|
+
await this.sendLanguageMenu();
|
|
2494
|
+
return;
|
|
2495
|
+
}
|
|
2496
|
+
if (data.startsWith("lang:")) {
|
|
2497
|
+
const lang = data.slice(5);
|
|
2498
|
+
if (lang === "en" || lang === "ar") {
|
|
2499
|
+
this.language = lang;
|
|
2500
|
+
this.cfgManager.config.language = lang;
|
|
2501
|
+
this.cfgManager.saveGlobal();
|
|
2502
|
+
await this.channel.sendMessage(
|
|
2503
|
+
this.allowedChatId,
|
|
2504
|
+
t("lang_changed", this.language),
|
|
2505
|
+
{ replyMarkup: this.getMainKeyboard() }
|
|
2506
|
+
);
|
|
2507
|
+
}
|
|
2508
|
+
return;
|
|
2509
|
+
}
|
|
2510
|
+
if (data === "ho") {
|
|
2511
|
+
await this.sendHandoffReport();
|
|
2512
|
+
return;
|
|
2513
|
+
}
|
|
2514
|
+
if (data === "hp") {
|
|
2515
|
+
await this.channel.sendMessage(
|
|
2516
|
+
this.allowedChatId,
|
|
2517
|
+
`\u26A1 <b>AgentGram Commands & Mission Control</b>
|
|
2518
|
+
${t("help_title", this.language)}`,
|
|
2519
|
+
{ replyMarkup: this.getMainKeyboard() }
|
|
2520
|
+
);
|
|
2521
|
+
return;
|
|
2522
|
+
}
|
|
2523
|
+
if (data === "stop") {
|
|
2524
|
+
await this.abortCurrentRun();
|
|
2525
|
+
return;
|
|
1990
2526
|
}
|
|
1991
2527
|
}
|
|
1992
2528
|
async handleEngineEvent(event) {
|
|
@@ -2006,7 +2542,7 @@ ${t("help_title", this.language)}`,
|
|
|
2006
2542
|
if (decision === "reject") {
|
|
2007
2543
|
await this.engine.replyPermission(permId, "reject");
|
|
2008
2544
|
if (reason) {
|
|
2009
|
-
await this.channel.sendMessage(this.allowedChatId, `\u26D4 ${
|
|
2545
|
+
await this.channel.sendMessage(this.allowedChatId, `\u26D4 ${escapeHtml(reason)}`);
|
|
2010
2546
|
}
|
|
2011
2547
|
return;
|
|
2012
2548
|
}
|
|
@@ -2014,9 +2550,9 @@ ${t("help_title", this.language)}`,
|
|
|
2014
2550
|
await this.channel.sendMessage(
|
|
2015
2551
|
this.allowedChatId,
|
|
2016
2552
|
t("permission_prompt", this.language, {
|
|
2017
|
-
tool:
|
|
2018
|
-
pattern:
|
|
2019
|
-
details: cmd ? `<code>${
|
|
2553
|
+
tool: escapeHtml(tool),
|
|
2554
|
+
pattern: escapeHtml(String(props.patterns || "*")),
|
|
2555
|
+
details: cmd ? `<code>${escapeHtml(cmd.slice(0, 150))}</code>` : ""
|
|
2020
2556
|
}),
|
|
2021
2557
|
{ replyMarkup: kb }
|
|
2022
2558
|
);
|
|
@@ -2057,11 +2593,11 @@ ${t("help_title", this.language)}`,
|
|
|
2057
2593
|
const statusText = run.done ? "Finished" : run.busy ? "Executing" : "Waiting";
|
|
2058
2594
|
return `
|
|
2059
2595
|
\u26A1 <b>AgentGram \xB7 Live Mission Control</b>
|
|
2060
|
-
Agent: \u{1F9E0} <code>${
|
|
2061
|
-
Channel: \u{1F4E1} <b>${
|
|
2596
|
+
Agent: \u{1F9E0} <code>${escapeHtml(run.agent)}</code> (${escapeHtml(this.engine.name)}) | Mode: \u{1F512} <b>${run.mode}</b>
|
|
2597
|
+
Channel: \u{1F4E1} <b>${escapeHtml(this.channel.name)}</b>
|
|
2062
2598
|
Status: ${statusIcon} <b>${statusText}</b> \xB7 \u23F3 ${elapsed}s
|
|
2063
2599
|
Commands: \u2699\uFE0F ${run.cmds} \xB7 Files: \u{1F4DD} ${run.files.size}
|
|
2064
|
-
Workspace: \u{1F4C1} <code>${
|
|
2600
|
+
Workspace: \u{1F4C1} <code>${escapeHtml(path3.basename(this.targetDir))}</code>
|
|
2065
2601
|
`.trim();
|
|
2066
2602
|
}
|
|
2067
2603
|
async updateMissionCard(final = false) {
|
|
@@ -2080,49 +2616,382 @@ Workspace: \u{1F4C1} <code>${escapeHtml2(path3.basename(this.targetDir))}</code>
|
|
|
2080
2616
|
} catch {
|
|
2081
2617
|
}
|
|
2082
2618
|
}
|
|
2619
|
+
/**
|
|
2620
|
+
* The complete, feature-rich 5-row interactive home keyboard with all 14 buttons.
|
|
2621
|
+
*/
|
|
2083
2622
|
getMainKeyboard() {
|
|
2084
2623
|
const rows = [
|
|
2085
2624
|
[
|
|
2086
|
-
{ text: t("
|
|
2087
|
-
{ text: t("
|
|
2625
|
+
{ text: t("btn_agents", this.language), callback_data: "menu:ag" },
|
|
2626
|
+
{ text: t("btn_models", this.language), callback_data: "menu:md" },
|
|
2088
2627
|
{ text: t("btn_mode", this.language), callback_data: "menu:mo" }
|
|
2089
2628
|
],
|
|
2090
2629
|
[
|
|
2630
|
+
{ text: t("btn_sessions", this.language), callback_data: "menu:se" },
|
|
2631
|
+
{ text: t("btn_new", this.language), callback_data: "new" },
|
|
2632
|
+
{ text: t("btn_stop", this.language), callback_data: "stop" }
|
|
2633
|
+
],
|
|
2634
|
+
[
|
|
2635
|
+
{ text: t("btn_status", this.language), callback_data: "st" },
|
|
2091
2636
|
{ text: t("btn_workspaces", this.language), callback_data: "menu:ws" },
|
|
2637
|
+
{ text: t("btn_diff", this.language), callback_data: "diff" }
|
|
2638
|
+
],
|
|
2639
|
+
[
|
|
2640
|
+
{ text: t("btn_skills", this.language), callback_data: "menu:sk" },
|
|
2641
|
+
{ text: t("btn_usage", this.language), callback_data: "us" },
|
|
2092
2642
|
{ text: t("btn_language", this.language), callback_data: "menu:lg" }
|
|
2643
|
+
],
|
|
2644
|
+
[
|
|
2645
|
+
{ text: t("btn_handoff", this.language), callback_data: "ho" },
|
|
2646
|
+
{ text: t("btn_help", this.language), callback_data: "hp" }
|
|
2093
2647
|
]
|
|
2094
2648
|
];
|
|
2649
|
+
return this.wrapKeyboard(rows);
|
|
2650
|
+
}
|
|
2651
|
+
wrapKeyboard(rows) {
|
|
2652
|
+
const cleanRows = rows.map(
|
|
2653
|
+
(r) => r.map((btn) => ({
|
|
2654
|
+
text: stripHtml(btn.text).replace(/^[⚡\s]+/, "").trim(),
|
|
2655
|
+
callback_data: btn.callback_data
|
|
2656
|
+
}))
|
|
2657
|
+
);
|
|
2095
2658
|
return {
|
|
2096
|
-
rows:
|
|
2659
|
+
rows: cleanRows.map(
|
|
2097
2660
|
(r) => r.map((btn) => ({
|
|
2098
2661
|
text: btn.text,
|
|
2099
2662
|
callbackData: btn.callback_data,
|
|
2100
2663
|
callback_data: btn.callback_data
|
|
2101
2664
|
}))
|
|
2102
2665
|
),
|
|
2103
|
-
inline_keyboard:
|
|
2666
|
+
inline_keyboard: cleanRows
|
|
2104
2667
|
};
|
|
2105
2668
|
}
|
|
2669
|
+
async sendAgentsMenu() {
|
|
2670
|
+
const agents = ["build", "delegate", "explorer", "code-review"];
|
|
2671
|
+
const rows = [];
|
|
2672
|
+
let currentRow = [];
|
|
2673
|
+
for (const a of agents) {
|
|
2674
|
+
const isCurrent = a === this.currentAgent;
|
|
2675
|
+
currentRow.push({
|
|
2676
|
+
text: `${isCurrent ? "\u25CF " : ""}${a}`,
|
|
2677
|
+
callback_data: `ag:${a}`
|
|
2678
|
+
});
|
|
2679
|
+
if (currentRow.length === 2) {
|
|
2680
|
+
rows.push(currentRow);
|
|
2681
|
+
currentRow = [];
|
|
2682
|
+
}
|
|
2683
|
+
}
|
|
2684
|
+
if (currentRow.length > 0) rows.push(currentRow);
|
|
2685
|
+
rows.push([{ text: t("btn_back", this.language), callback_data: "menu:home" }]);
|
|
2686
|
+
await this.channel.sendMessage(
|
|
2687
|
+
this.allowedChatId,
|
|
2688
|
+
t("select_agent", this.language, { agent: escapeHtml(this.currentAgent) }),
|
|
2689
|
+
{ replyMarkup: this.wrapKeyboard(rows) }
|
|
2690
|
+
);
|
|
2691
|
+
}
|
|
2692
|
+
async sendModelsMenu(page = 0) {
|
|
2693
|
+
const favs = this.cfgManager.config.favoriteModels || [];
|
|
2694
|
+
let engineModels = [];
|
|
2695
|
+
if (typeof this.engine.listModels === "function") {
|
|
2696
|
+
try {
|
|
2697
|
+
const raw = await this.engine.listModels();
|
|
2698
|
+
engineModels = (raw || []).map((m) => m.id);
|
|
2699
|
+
} catch {
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2702
|
+
const standardCatalog = getStandardModelCatalog();
|
|
2703
|
+
const combinedSet = /* @__PURE__ */ new Set([...favs, ...engineModels, ...standardCatalog]);
|
|
2704
|
+
const allModels = Array.from(combinedSet);
|
|
2705
|
+
const rest = allModels.filter((m) => !favs.includes(m));
|
|
2706
|
+
const pageSize = 6;
|
|
2707
|
+
const pool = page === 0 ? favs : rest.slice((page - 1) * pageSize, page * pageSize);
|
|
2708
|
+
const totalPages = Math.ceil(rest.length / pageSize) || 1;
|
|
2709
|
+
const rows = pool.map((m, idx) => {
|
|
2710
|
+
const meta = resolveModelMetadata(m);
|
|
2711
|
+
const isCurrent = m === this.currentModel;
|
|
2712
|
+
const cleanName = meta.name.length > 20 ? meta.name.slice(0, 18) + "\u2026" : meta.name;
|
|
2713
|
+
return [
|
|
2714
|
+
{
|
|
2715
|
+
text: `${isCurrent ? "\u25CF " : ""}${cleanName} \xB7 ${meta.contextWindow}`,
|
|
2716
|
+
callback_data: page === 0 ? `md:${idx}` : `md:raw:${m}`
|
|
2717
|
+
}
|
|
2718
|
+
];
|
|
2719
|
+
});
|
|
2720
|
+
if (page === 0) {
|
|
2721
|
+
if (rest.length > 0) {
|
|
2722
|
+
rows.push([{ text: t("btn_all_models", this.language), callback_data: "pg:1" }]);
|
|
2723
|
+
}
|
|
2724
|
+
rows.push([{ text: t("btn_back", this.language), callback_data: "menu:home" }]);
|
|
2725
|
+
} else {
|
|
2726
|
+
const pagRow = [
|
|
2727
|
+
{ text: t("btn_favorites", this.language), callback_data: "pg:0" }
|
|
2728
|
+
];
|
|
2729
|
+
if (rest.length > page * pageSize) {
|
|
2730
|
+
pagRow.push({ text: t("btn_next", this.language), callback_data: `pg:${page + 1}` });
|
|
2731
|
+
}
|
|
2732
|
+
rows.push(pagRow);
|
|
2733
|
+
rows.push([{ text: t("btn_back", this.language), callback_data: "menu:md" }]);
|
|
2734
|
+
}
|
|
2735
|
+
const curMeta = resolveModelMetadata(this.currentModel);
|
|
2736
|
+
let cardText = this.language === "ar" ? `\u{1F916} <b>\u0646\u0645\u0627\u0630\u062C \u0627\u0644\u0630\u0643\u0627\u0621 \u0627\u0644\u0627\u0635\u0637\u0646\u0627\u0639\u064A \u0648\u0645\u0633\u0627\u062D\u0629 \u0627\u0644\u0633\u064A\u0627\u0642</b> ${page > 0 ? `(\u0635\u0641\u062D\u0629 ${page} \u0645\u0646 ${totalPages})` : "(\u0627\u0644\u0645\u0641\u0636\u0644\u0629)"}
|
|
2737
|
+
\u0627\u0644\u0646\u0645\u0648\u0630\u062C \u0627\u0644\u0646\u0634\u0637: <b>${escapeHtml(curMeta.name)}</b> (<code>${escapeHtml(curMeta.contextWindow)}</code>)
|
|
2738
|
+
|
|
2739
|
+
` : `\u{1F916} <b>AI Models & Context Windows</b> ${page > 0 ? `(Page ${page} of ${totalPages})` : "(Favorites)"}
|
|
2740
|
+
Active: <b>${escapeHtml(curMeta.name)}</b> (<code>${escapeHtml(curMeta.contextWindow)}</code>)
|
|
2741
|
+
|
|
2742
|
+
`;
|
|
2743
|
+
for (const m of pool) {
|
|
2744
|
+
const meta = resolveModelMetadata(m);
|
|
2745
|
+
const isCurrent = m === this.currentModel;
|
|
2746
|
+
cardText += `${isCurrent ? "\u25CF" : "\u2022"} <b>${escapeHtml(meta.name)}</b> (<code>${escapeHtml(meta.provider)}</code>)
|
|
2747
|
+
`;
|
|
2748
|
+
cardText += ` <code>\u0627\u0644\u0633\u064A\u0627\u0642: ${escapeHtml(meta.contextWindow)} | ${escapeHtml(meta.tag)}</code>
|
|
2749
|
+
`;
|
|
2750
|
+
}
|
|
2751
|
+
cardText += this.language === "ar" ? `
|
|
2752
|
+
<i>\u0627\u0636\u063A\u0637 \u0639\u0644\u0649 \u0623\u064A \u0646\u0645\u0648\u0630\u062C \u0623\u062F\u0646\u0627\u0647 \u0644\u0644\u062A\u0628\u062F\u064A\u0644 \u0625\u0644\u064A\u0647 \u0641\u0648\u0631\u0627\u064B:</i>` : `
|
|
2753
|
+
<i>Tap any model below to activate immediately:</i>`;
|
|
2754
|
+
await this.channel.sendMessage(
|
|
2755
|
+
this.allowedChatId,
|
|
2756
|
+
cardText.trim(),
|
|
2757
|
+
{ replyMarkup: this.wrapKeyboard(rows) }
|
|
2758
|
+
);
|
|
2759
|
+
}
|
|
2106
2760
|
async sendModeMenu() {
|
|
2107
2761
|
const rows = [
|
|
2108
2762
|
[
|
|
2109
|
-
{ text: "\u{1F512} Read-Only
|
|
2110
|
-
{ text: "\u{1F528} Build (Interactive)
|
|
2111
|
-
{ text: "\u26A1 Auto Mode
|
|
2763
|
+
{ text: `${this.currentMode === "read" ? "\u25CF " : ""}\u{1F512} Read-Only`, callback_data: "mo:read" },
|
|
2764
|
+
{ text: `${this.currentMode === "build" ? "\u25CF " : ""}\u{1F528} Build (Interactive)`, callback_data: "mo:build" },
|
|
2765
|
+
{ text: `${this.currentMode === "auto" ? "\u25CF " : ""}\u26A1 Auto Mode`, callback_data: "mo:auto" }
|
|
2766
|
+
],
|
|
2767
|
+
[
|
|
2768
|
+
{ text: t("btn_back", this.language), callback_data: "menu:home" }
|
|
2112
2769
|
]
|
|
2113
2770
|
];
|
|
2114
|
-
const kb = {
|
|
2115
|
-
rows: rows.map(
|
|
2116
|
-
(r) => r.map((b) => ({ text: b.text, callbackData: b.callback_data, callback_data: b.callback_data }))
|
|
2117
|
-
),
|
|
2118
|
-
inline_keyboard: rows
|
|
2119
|
-
};
|
|
2120
2771
|
await this.channel.sendMessage(
|
|
2121
2772
|
this.allowedChatId,
|
|
2122
2773
|
t("select_mode", this.language, { mode: this.currentMode }),
|
|
2123
|
-
{ replyMarkup:
|
|
2774
|
+
{ replyMarkup: this.wrapKeyboard(rows) }
|
|
2775
|
+
);
|
|
2776
|
+
}
|
|
2777
|
+
async sendSessionsMenu() {
|
|
2778
|
+
const rows = [
|
|
2779
|
+
[{ text: "\u2728 " + t("btn_new", this.language), callback_data: "new" }]
|
|
2780
|
+
];
|
|
2781
|
+
if (this.activeRun && this.activeRun.sessionId) {
|
|
2782
|
+
rows.unshift([{
|
|
2783
|
+
text: `\u25CF Session: ${this.activeRun.sessionId.slice(0, 16)}\u2026`,
|
|
2784
|
+
callback_data: `se:${this.activeRun.sessionId}`
|
|
2785
|
+
}]);
|
|
2786
|
+
}
|
|
2787
|
+
rows.push([{ text: t("btn_back", this.language), callback_data: "menu:home" }]);
|
|
2788
|
+
await this.channel.sendMessage(
|
|
2789
|
+
this.allowedChatId,
|
|
2790
|
+
`\u{1F4C2} <b>Active Sessions</b>
|
|
2791
|
+
Current: <code>${escapeHtml(this.activeRun?.sessionId || "None (New)")}</code>`,
|
|
2792
|
+
{ replyMarkup: this.wrapKeyboard(rows) }
|
|
2124
2793
|
);
|
|
2125
2794
|
}
|
|
2795
|
+
async sendStatusReport() {
|
|
2796
|
+
let branch = "unknown";
|
|
2797
|
+
let dirtyCount = 0;
|
|
2798
|
+
try {
|
|
2799
|
+
const bRes = child_process3.spawnSync("git", ["branch", "--show-current"], {
|
|
2800
|
+
cwd: this.targetDir,
|
|
2801
|
+
encoding: "utf-8",
|
|
2802
|
+
timeout: 5e3
|
|
2803
|
+
});
|
|
2804
|
+
if (bRes.status === 0) branch = bRes.stdout.trim() || "main";
|
|
2805
|
+
const sRes = child_process3.spawnSync("git", ["status", "--porcelain"], {
|
|
2806
|
+
cwd: this.targetDir,
|
|
2807
|
+
encoding: "utf-8",
|
|
2808
|
+
timeout: 5e3
|
|
2809
|
+
});
|
|
2810
|
+
if (sRes.status === 0) {
|
|
2811
|
+
dirtyCount = sRes.stdout.trim().split("\n").filter(Boolean).length;
|
|
2812
|
+
}
|
|
2813
|
+
} catch {
|
|
2814
|
+
}
|
|
2815
|
+
const isBusy = this.activeRun && this.activeRun.busy ? "\u{1F7E2} Running" : "\u23F8 Idle";
|
|
2816
|
+
const text = `
|
|
2817
|
+
\u{1F4CA} <b>System & Mission Control Status</b>
|
|
2818
|
+
\u{1F4C1} Workspace: <b>${escapeHtml(path3.basename(this.targetDir))}</b>
|
|
2819
|
+
<code>${escapeHtml(this.targetDir)}</code>
|
|
2820
|
+
\u{1F9E0} Agent: <b>${escapeHtml(this.currentAgent)}</b> (${escapeHtml(this.engine.name)})
|
|
2821
|
+
\u{1F916} Model: <b>${escapeHtml(this.currentModel || "Default")}</b>
|
|
2822
|
+
\u{1F512} Mode: <b>${escapeHtml(this.currentMode)}</b>
|
|
2823
|
+
\u{1F4E1} Channel: <b>${escapeHtml(this.channel.name)}</b>
|
|
2824
|
+
\u{1F4C2} Session: <code>${escapeHtml(this.activeRun?.sessionId || "None (Ready)")}</code>
|
|
2825
|
+
\u23F3 Status: <b>${isBusy}</b>
|
|
2826
|
+
\u{1F33F} Git Branch: <code>${escapeHtml(branch)}</code> \xB7 Modified files: <b>${dirtyCount}</b>
|
|
2827
|
+
`.trim();
|
|
2828
|
+
await this.channel.sendMessage(this.allowedChatId, text, {
|
|
2829
|
+
replyMarkup: this.getMainKeyboard()
|
|
2830
|
+
});
|
|
2831
|
+
}
|
|
2832
|
+
getAllAvailableSkills() {
|
|
2833
|
+
const candidates = [
|
|
2834
|
+
path3.join(this.targetDir, ".agents", "skills"),
|
|
2835
|
+
path3.join(this.targetDir, "docs", "ai", "skills"),
|
|
2836
|
+
path3.join(this.targetDir, ".gemini", "skills")
|
|
2837
|
+
];
|
|
2838
|
+
const map = /* @__PURE__ */ new Map();
|
|
2839
|
+
for (const dir of candidates) {
|
|
2840
|
+
if (!fs3.existsSync(dir)) continue;
|
|
2841
|
+
try {
|
|
2842
|
+
const items = fs3.readdirSync(dir, { withFileTypes: true });
|
|
2843
|
+
for (const item of items) {
|
|
2844
|
+
if (!item.isDirectory() && !item.isSymbolicLink()) continue;
|
|
2845
|
+
if (item.name.startsWith(".")) continue;
|
|
2846
|
+
const raw = item.name;
|
|
2847
|
+
const clean = raw.replace(/^\d+-/, "");
|
|
2848
|
+
if (!map.has(clean)) {
|
|
2849
|
+
let desc;
|
|
2850
|
+
const skillMd = path3.join(dir, raw, "SKILL.md");
|
|
2851
|
+
if (fs3.existsSync(skillMd)) {
|
|
2852
|
+
try {
|
|
2853
|
+
const head = fs3.readFileSync(skillMd, "utf-8").slice(0, 600);
|
|
2854
|
+
const m = head.match(/description:\s*["']?([^"'\n\r]+)/i);
|
|
2855
|
+
if (m && m[1]) {
|
|
2856
|
+
desc = m[1].replace(/^[>"\s]+|[<"\s]+$/g, "").trim();
|
|
2857
|
+
}
|
|
2858
|
+
} catch {
|
|
2859
|
+
}
|
|
2860
|
+
}
|
|
2861
|
+
map.set(clean, {
|
|
2862
|
+
id: clean,
|
|
2863
|
+
name: clean,
|
|
2864
|
+
description: desc
|
|
2865
|
+
});
|
|
2866
|
+
}
|
|
2867
|
+
}
|
|
2868
|
+
} catch {
|
|
2869
|
+
}
|
|
2870
|
+
}
|
|
2871
|
+
if (map.size === 0) {
|
|
2872
|
+
const defaults = [
|
|
2873
|
+
"frontend",
|
|
2874
|
+
"query-performance",
|
|
2875
|
+
"erp-debug",
|
|
2876
|
+
"security-audit",
|
|
2877
|
+
"git-hygiene",
|
|
2878
|
+
"financial-expert",
|
|
2879
|
+
"rveta-core",
|
|
2880
|
+
"laravel-architecture"
|
|
2881
|
+
];
|
|
2882
|
+
defaults.forEach((d) => map.set(d, { id: d, name: d }));
|
|
2883
|
+
}
|
|
2884
|
+
return Array.from(map.values()).sort((a, b) => a.name.localeCompare(b.name));
|
|
2885
|
+
}
|
|
2886
|
+
async sendSkillsMenu(page = 0) {
|
|
2887
|
+
const allSkills = this.getAllAvailableSkills();
|
|
2888
|
+
const pageSize = 8;
|
|
2889
|
+
const totalPages = Math.ceil(allSkills.length / pageSize) || 1;
|
|
2890
|
+
const safePage = Math.min(Math.max(0, page), totalPages - 1);
|
|
2891
|
+
const pool = allSkills.slice(safePage * pageSize, (safePage + 1) * pageSize);
|
|
2892
|
+
const rows = [];
|
|
2893
|
+
let currentRow = [];
|
|
2894
|
+
for (const sk of pool) {
|
|
2895
|
+
const isCurrent = sk.name === this.activeSkill;
|
|
2896
|
+
currentRow.push({
|
|
2897
|
+
text: `${isCurrent ? "\u25CF " : ""}\u{1F9F0} ${sk.name}`,
|
|
2898
|
+
callback_data: `sk:${sk.name}`
|
|
2899
|
+
});
|
|
2900
|
+
if (currentRow.length === 2) {
|
|
2901
|
+
rows.push(currentRow);
|
|
2902
|
+
currentRow = [];
|
|
2903
|
+
}
|
|
2904
|
+
}
|
|
2905
|
+
if (currentRow.length > 0) rows.push(currentRow);
|
|
2906
|
+
const pagRow = [];
|
|
2907
|
+
if (safePage > 0) {
|
|
2908
|
+
pagRow.push({ text: "\u2B05\uFE0F \u0627\u0644\u0633\u0627\u0628\u0642", callback_data: `skpage:${safePage - 1}` });
|
|
2909
|
+
}
|
|
2910
|
+
if (safePage < totalPages - 1) {
|
|
2911
|
+
pagRow.push({ text: "\u27A1\uFE0F \u0627\u0644\u0645\u0632\u064A\u062F \u0645\u0646 \u0627\u0644\u0645\u0647\u0627\u0631\u0627\u062A", callback_data: `skpage:${safePage + 1}` });
|
|
2912
|
+
}
|
|
2913
|
+
if (pagRow.length > 0) {
|
|
2914
|
+
rows.push(pagRow);
|
|
2915
|
+
}
|
|
2916
|
+
rows.push([{ text: t("btn_back", this.language), callback_data: "menu:home" }]);
|
|
2917
|
+
let cardText = this.language === "ar" ? `\u{1F9F0} <b>\u0645\u0647\u0627\u0631\u0627\u062A \u0648\u0643\u0644\u0627\u0621 \u0627\u0644\u0630\u0643\u0627\u0621 \u0627\u0644\u0627\u0635\u0637\u0646\u0627\u0639\u064A (Agent Skills)</b> (\u0635\u0641\u062D\u0629 ${safePage + 1} \u0645\u0646 ${totalPages} \xB7 \u0625\u062C\u0645\u0627\u0644\u064A ${allSkills.length} \u0645\u0647\u0627\u0631\u0629)
|
|
2918
|
+
\u0627\u0644\u0645\u0647\u0627\u0631\u0629 \u0627\u0644\u0645\u0641\u0639\u0644\u0629: <b>${escapeHtml(this.activeSkill || "\u0628\u062F\u0648\u0646 (\u0648\u0643\u064A\u0644 \u0639\u0627\u0645)")}</b>
|
|
2919
|
+
|
|
2920
|
+
` : `\u{1F9F0} <b>Available Agent Skills</b> (Page ${safePage + 1} of ${totalPages} \xB7 Total: ${allSkills.length})
|
|
2921
|
+
Active: <b>${escapeHtml(this.activeSkill || "None (Standard Agent)")}</b>
|
|
2922
|
+
|
|
2923
|
+
`;
|
|
2924
|
+
for (const sk of pool) {
|
|
2925
|
+
const isCurrent = sk.name === this.activeSkill;
|
|
2926
|
+
const descSnippet = sk.description ? sk.description.slice(0, 60) + (sk.description.length > 60 ? "\u2026" : "") : "\u0645\u0647\u0627\u0631\u0629 \u0645\u062A\u062E\u0635\u0635\u0629";
|
|
2927
|
+
cardText += `${isCurrent ? "\u25CF" : "\u2022"} <b>${escapeHtml(sk.name)}</b>
|
|
2928
|
+
`;
|
|
2929
|
+
cardText += ` <code>${escapeHtml(descSnippet)}</code>
|
|
2930
|
+
`;
|
|
2931
|
+
}
|
|
2932
|
+
cardText += this.language === "ar" ? `
|
|
2933
|
+
<i>\u0627\u062E\u062A\u0631 \u0627\u0644\u0645\u0647\u0627\u0631\u0629 \u0644\u062A\u0648\u062C\u064A\u0647 \u0627\u0644\u0648\u0643\u064A\u0644 \u0627\u0644\u0628\u0631\u0645\u062C\u064A \u0644\u0644\u0639\u0645\u0644 \u0628\u0647\u0627 \u0641\u0648\u0631\u0627\u064B:</i>` : `
|
|
2934
|
+
<i>Select a skill to prime the agent for execution:</i>`;
|
|
2935
|
+
await this.channel.sendMessage(
|
|
2936
|
+
this.allowedChatId,
|
|
2937
|
+
cardText.trim(),
|
|
2938
|
+
{ replyMarkup: this.wrapKeyboard(rows) }
|
|
2939
|
+
);
|
|
2940
|
+
}
|
|
2941
|
+
async sendUsageReport() {
|
|
2942
|
+
const cfg = this.cfgManager.config;
|
|
2943
|
+
const text = `
|
|
2944
|
+
\u{1F4C8} <b>Resource Usage & Quotas</b>
|
|
2945
|
+
\u2022 Daily Limit: <b>${cfg.dailyLimit} tasks</b>
|
|
2946
|
+
\u2022 Task Timeout: <b>${Math.round(cfg.runTimeout / 60)} minutes</b>
|
|
2947
|
+
\u2022 Workspace ID: <code>${escapeHtml(this.cfgManager.workspaceId)}</code>
|
|
2948
|
+
\u2022 Platform: <b>${os2.platform()} (${os2.arch()})</b>
|
|
2949
|
+
`.trim();
|
|
2950
|
+
await this.channel.sendMessage(this.allowedChatId, text, {
|
|
2951
|
+
replyMarkup: this.getMainKeyboard()
|
|
2952
|
+
});
|
|
2953
|
+
}
|
|
2954
|
+
async sendLanguageMenu() {
|
|
2955
|
+
const cur = this.language;
|
|
2956
|
+
const rows = [
|
|
2957
|
+
[{ text: `${cur === "en" ? "\u25CF " : ""}\u{1F1FA}\u{1F1F8} English`, callback_data: "lang:en" }],
|
|
2958
|
+
[{ text: `${cur === "ar" ? "\u25CF " : ""}\u{1F1F8}\u{1F1E6} \u0627\u0644\u0639\u0631\u0628\u064A\u0629`, callback_data: "lang:ar" }],
|
|
2959
|
+
[{ text: t("btn_back", this.language), callback_data: "menu:home" }]
|
|
2960
|
+
];
|
|
2961
|
+
await this.channel.sendMessage(
|
|
2962
|
+
this.allowedChatId,
|
|
2963
|
+
t("select_language", this.language),
|
|
2964
|
+
{ replyMarkup: this.wrapKeyboard(rows) }
|
|
2965
|
+
);
|
|
2966
|
+
}
|
|
2967
|
+
async sendHandoffReport() {
|
|
2968
|
+
let branch = "unknown";
|
|
2969
|
+
let dirtyLines = [];
|
|
2970
|
+
let commits = [];
|
|
2971
|
+
try {
|
|
2972
|
+
const b = child_process3.spawnSync("git", ["branch", "--show-current"], { cwd: this.targetDir, encoding: "utf-8", timeout: 5e3 });
|
|
2973
|
+
if (b.status === 0) branch = b.stdout.trim() || "main";
|
|
2974
|
+
const s = child_process3.spawnSync("git", ["status", "--porcelain"], { cwd: this.targetDir, encoding: "utf-8", timeout: 5e3 });
|
|
2975
|
+
if (s.status === 0) dirtyLines = s.stdout.trim().split("\n").filter(Boolean);
|
|
2976
|
+
const c = child_process3.spawnSync("git", ["log", "-5", "--oneline"], { cwd: this.targetDir, encoding: "utf-8", timeout: 5e3 });
|
|
2977
|
+
if (c.status === 0) commits = c.stdout.trim().split("\n").filter(Boolean);
|
|
2978
|
+
} catch {
|
|
2979
|
+
}
|
|
2980
|
+
const dirtyPreview = dirtyLines.slice(0, 10).map((l) => ` ${l}`).join("\n") || " (Clean working tree)";
|
|
2981
|
+
const commitsPreview = commits.map((c) => ` ${c}`).join("\n") || " (No commits)";
|
|
2982
|
+
const text = `
|
|
2983
|
+
<b>HANDOFF \u2014 Resume task in another tool</b>
|
|
2984
|
+
Repo: <code>${escapeHtml(this.targetDir)}</code> (Branch: <code>${escapeHtml(branch)}</code>)
|
|
2985
|
+
Uncommitted files: <b>${dirtyLines.length}</b>
|
|
2986
|
+
<pre><code>${escapeHtml(dirtyPreview)}</code></pre>
|
|
2987
|
+
Last commits:
|
|
2988
|
+
<pre><code>${escapeHtml(commitsPreview)}</code></pre>
|
|
2989
|
+
Agent: <b>${escapeHtml(this.currentAgent)}</b> | Mode: <b>${escapeHtml(this.currentMode)}</b>
|
|
2990
|
+
`.trim();
|
|
2991
|
+
await this.channel.sendMessage(this.allowedChatId, text, {
|
|
2992
|
+
replyMarkup: this.getMainKeyboard()
|
|
2993
|
+
});
|
|
2994
|
+
}
|
|
2126
2995
|
async sendWorkspaceMenu() {
|
|
2127
2996
|
const workspaces = this.cfgManager.config.workspaces;
|
|
2128
2997
|
const rows = workspaces.map((ws, i) => [
|
|
@@ -2131,16 +3000,11 @@ Workspace: \u{1F4C1} <code>${escapeHtml2(path3.basename(this.targetDir))}</code>
|
|
|
2131
3000
|
callback_data: `ws:${i}`
|
|
2132
3001
|
}
|
|
2133
3002
|
]);
|
|
2134
|
-
|
|
2135
|
-
rows: rows.map(
|
|
2136
|
-
(r) => r.map((b) => ({ text: b.text, callbackData: b.callback_data, callback_data: b.callback_data }))
|
|
2137
|
-
),
|
|
2138
|
-
inline_keyboard: rows
|
|
2139
|
-
};
|
|
3003
|
+
rows.push([{ text: t("btn_back", this.language), callback_data: "menu:home" }]);
|
|
2140
3004
|
await this.channel.sendMessage(
|
|
2141
3005
|
this.allowedChatId,
|
|
2142
|
-
t("select_workspace", this.language, { ws:
|
|
2143
|
-
{ replyMarkup:
|
|
3006
|
+
t("select_workspace", this.language, { ws: escapeHtml(this.targetDir) }),
|
|
3007
|
+
{ replyMarkup: this.wrapKeyboard(rows) }
|
|
2144
3008
|
);
|
|
2145
3009
|
}
|
|
2146
3010
|
async switchWorkspace(newPath) {
|
|
@@ -2148,14 +3012,14 @@ Workspace: \u{1F4C1} <code>${escapeHtml2(path3.basename(this.targetDir))}</code>
|
|
|
2148
3012
|
if (!fs3.existsSync(resolved)) {
|
|
2149
3013
|
await this.channel.sendMessage(
|
|
2150
3014
|
this.allowedChatId,
|
|
2151
|
-
t("ws_not_found", this.language, { path:
|
|
3015
|
+
t("ws_not_found", this.language, { path: escapeHtml(resolved) })
|
|
2152
3016
|
);
|
|
2153
3017
|
return;
|
|
2154
3018
|
}
|
|
2155
3019
|
if (this.activeRun && this.activeRun.busy) {
|
|
2156
3020
|
await this.channel.sendMessage(
|
|
2157
3021
|
this.allowedChatId,
|
|
2158
|
-
t("ws_busy", this.language, { ws:
|
|
3022
|
+
t("ws_busy", this.language, { ws: escapeHtml(this.targetDir) })
|
|
2159
3023
|
);
|
|
2160
3024
|
return;
|
|
2161
3025
|
}
|
|
@@ -2170,8 +3034,8 @@ Workspace: \u{1F4C1} <code>${escapeHtml2(path3.basename(this.targetDir))}</code>
|
|
|
2170
3034
|
await this.channel.sendMessage(
|
|
2171
3035
|
this.allowedChatId,
|
|
2172
3036
|
t("ws_changed", this.language, {
|
|
2173
|
-
name:
|
|
2174
|
-
ws:
|
|
3037
|
+
name: escapeHtml(path3.basename(resolved)),
|
|
3038
|
+
ws: escapeHtml(resolved),
|
|
2175
3039
|
branch: "main",
|
|
2176
3040
|
dirty: "0"
|
|
2177
3041
|
}),
|
|
@@ -2186,7 +3050,7 @@ Workspace: \u{1F4C1} <code>${escapeHtml2(path3.basename(this.targetDir))}</code>
|
|
|
2186
3050
|
return;
|
|
2187
3051
|
}
|
|
2188
3052
|
const preview = diff.length <= 3500 ? diff : diff.slice(0, 3500) + "\n\u2026 (truncated)";
|
|
2189
|
-
await this.channel.sendMessage(this.allowedChatId, `<pre><code>${
|
|
3053
|
+
await this.channel.sendMessage(this.allowedChatId, `<pre><code>${escapeHtml(preview)}</code></pre>`);
|
|
2190
3054
|
} catch (err) {
|
|
2191
3055
|
await this.channel.sendMessage(this.allowedChatId, `\u274C Diff error: ${err.message}`);
|
|
2192
3056
|
}
|
|
@@ -2211,36 +3075,36 @@ function getEntryPoint() {
|
|
|
2211
3075
|
if (fs4.existsSync(distEntry)) return distEntry;
|
|
2212
3076
|
return path4.join(root, "bin", "agentgram.js");
|
|
2213
3077
|
}
|
|
2214
|
-
var
|
|
3078
|
+
var os3, path4, fs4, import_node_child_process, MACOS_PLIST_NAME, LEGACY_MACOS_PLIST_NAME, MACOS_PLIST_DIR, MACOS_PLIST_PATH, LEGACY_MACOS_PLIST_PATH, LINUX_SERVICE_NAME, LEGACY_LINUX_SERVICE_NAME, LINUX_SERVICE_DIR, LINUX_SERVICE_PATH, LEGACY_LINUX_SERVICE_PATH, ServiceManager;
|
|
2215
3079
|
var init_service_manager = __esm({
|
|
2216
3080
|
"src/service/service-manager.ts"() {
|
|
2217
3081
|
"use strict";
|
|
2218
|
-
|
|
3082
|
+
os3 = __toESM(require("os"));
|
|
2219
3083
|
path4 = __toESM(require("path"));
|
|
2220
3084
|
fs4 = __toESM(require("fs"));
|
|
2221
3085
|
import_node_child_process = require("child_process");
|
|
2222
3086
|
MACOS_PLIST_NAME = "com.agentgram.plist";
|
|
2223
3087
|
LEGACY_MACOS_PLIST_NAME = "com.rumuze.edit.plist";
|
|
2224
|
-
MACOS_PLIST_DIR = path4.join(
|
|
3088
|
+
MACOS_PLIST_DIR = path4.join(os3.homedir(), "Library", "LaunchAgents");
|
|
2225
3089
|
MACOS_PLIST_PATH = path4.join(MACOS_PLIST_DIR, MACOS_PLIST_NAME);
|
|
2226
3090
|
LEGACY_MACOS_PLIST_PATH = path4.join(MACOS_PLIST_DIR, LEGACY_MACOS_PLIST_NAME);
|
|
2227
3091
|
LINUX_SERVICE_NAME = "agentgram.service";
|
|
2228
3092
|
LEGACY_LINUX_SERVICE_NAME = "rumuze-edit.service";
|
|
2229
|
-
LINUX_SERVICE_DIR = path4.join(
|
|
3093
|
+
LINUX_SERVICE_DIR = path4.join(os3.homedir(), ".config", "systemd", "user");
|
|
2230
3094
|
LINUX_SERVICE_PATH = path4.join(LINUX_SERVICE_DIR, LINUX_SERVICE_NAME);
|
|
2231
3095
|
LEGACY_LINUX_SERVICE_PATH = path4.join(LINUX_SERVICE_DIR, LEGACY_LINUX_SERVICE_NAME);
|
|
2232
3096
|
ServiceManager = class {
|
|
2233
3097
|
static install(targetDir) {
|
|
2234
|
-
const
|
|
3098
|
+
const platform4 = os3.platform();
|
|
2235
3099
|
const nodeExec = process.execPath;
|
|
2236
3100
|
const script = getEntryPoint();
|
|
2237
3101
|
const resolvedTarget = path4.resolve(targetDir || process.cwd());
|
|
2238
|
-
const logDir = path4.join(
|
|
3102
|
+
const logDir = path4.join(os3.homedir(), ".config", "agentgram");
|
|
2239
3103
|
try {
|
|
2240
3104
|
if (!fs4.existsSync(logDir)) fs4.mkdirSync(logDir, { recursive: true, mode: 448 });
|
|
2241
3105
|
} catch {
|
|
2242
3106
|
}
|
|
2243
|
-
if (
|
|
3107
|
+
if (platform4 === "darwin") {
|
|
2244
3108
|
try {
|
|
2245
3109
|
if (!fs4.existsSync(MACOS_PLIST_DIR)) {
|
|
2246
3110
|
fs4.mkdirSync(MACOS_PLIST_DIR, { recursive: true });
|
|
@@ -2248,7 +3112,7 @@ var init_service_manager = __esm({
|
|
|
2248
3112
|
(0, import_node_child_process.spawnSync)("launchctl", ["unload", MACOS_PLIST_PATH]);
|
|
2249
3113
|
(0, import_node_child_process.spawnSync)("launchctl", ["unload", LEGACY_MACOS_PLIST_PATH]);
|
|
2250
3114
|
let pathEnv = process.env.PATH || "/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin";
|
|
2251
|
-
const opencodeBin = path4.join(
|
|
3115
|
+
const opencodeBin = path4.join(os3.homedir(), ".opencode", "bin");
|
|
2252
3116
|
if (!pathEnv.includes(opencodeBin)) {
|
|
2253
3117
|
pathEnv = `${opencodeBin}:${pathEnv}`;
|
|
2254
3118
|
}
|
|
@@ -2299,11 +3163,16 @@ var init_service_manager = __esm({
|
|
|
2299
3163
|
} catch (err) {
|
|
2300
3164
|
return { success: false, message: err.message };
|
|
2301
3165
|
}
|
|
2302
|
-
} else if (
|
|
3166
|
+
} else if (platform4 === "linux") {
|
|
2303
3167
|
try {
|
|
2304
3168
|
if (!fs4.existsSync(LINUX_SERVICE_DIR)) {
|
|
2305
3169
|
fs4.mkdirSync(LINUX_SERVICE_DIR, { recursive: true });
|
|
2306
3170
|
}
|
|
3171
|
+
let pathEnv = process.env.PATH || "/usr/local/bin:/usr/bin:/bin";
|
|
3172
|
+
const opencodeBin = path4.join(os3.homedir(), ".opencode", "bin");
|
|
3173
|
+
if (!pathEnv.includes(opencodeBin)) {
|
|
3174
|
+
pathEnv = `${opencodeBin}:${pathEnv}`;
|
|
3175
|
+
}
|
|
2307
3176
|
const unitContent = `[Unit]
|
|
2308
3177
|
Description=AgentGram AI Telegram Mission Control
|
|
2309
3178
|
After=network.target
|
|
@@ -2311,6 +3180,7 @@ After=network.target
|
|
|
2311
3180
|
[Service]
|
|
2312
3181
|
Type=simple
|
|
2313
3182
|
WorkingDirectory=${resolvedTarget}
|
|
3183
|
+
Environment="PATH=${pathEnv}"
|
|
2314
3184
|
ExecStart=${nodeExec} ${script} start --dir ${resolvedTarget}
|
|
2315
3185
|
Restart=always
|
|
2316
3186
|
RestartSec=5
|
|
@@ -2333,12 +3203,12 @@ WantedBy=default.target
|
|
|
2333
3203
|
}
|
|
2334
3204
|
return {
|
|
2335
3205
|
success: false,
|
|
2336
|
-
message: `Background service automation is not currently supported on OS: ${
|
|
3206
|
+
message: `Background service automation is not currently supported on OS: ${platform4}`
|
|
2337
3207
|
};
|
|
2338
3208
|
}
|
|
2339
3209
|
static uninstall() {
|
|
2340
|
-
const
|
|
2341
|
-
if (
|
|
3210
|
+
const platform4 = os3.platform();
|
|
3211
|
+
if (platform4 === "darwin") {
|
|
2342
3212
|
for (const p of [MACOS_PLIST_PATH, LEGACY_MACOS_PLIST_PATH]) {
|
|
2343
3213
|
if (fs4.existsSync(p)) {
|
|
2344
3214
|
(0, import_node_child_process.spawnSync)("launchctl", ["unload", p]);
|
|
@@ -2349,11 +3219,12 @@ WantedBy=default.target
|
|
|
2349
3219
|
}
|
|
2350
3220
|
}
|
|
2351
3221
|
return { success: true, message: "Uninstalled macOS launchd service." };
|
|
2352
|
-
} else if (
|
|
2353
|
-
|
|
3222
|
+
} else if (platform4 === "linux") {
|
|
3223
|
+
const services = [
|
|
2354
3224
|
[LINUX_SERVICE_NAME, LINUX_SERVICE_PATH],
|
|
2355
3225
|
[LEGACY_LINUX_SERVICE_NAME, LEGACY_LINUX_SERVICE_PATH]
|
|
2356
|
-
]
|
|
3226
|
+
];
|
|
3227
|
+
for (const [name, p] of services) {
|
|
2357
3228
|
if (fs4.existsSync(p)) {
|
|
2358
3229
|
(0, import_node_child_process.spawnSync)("systemctl", ["--user", "stop", name]);
|
|
2359
3230
|
(0, import_node_child_process.spawnSync)("systemctl", ["--user", "disable", name]);
|
|
@@ -2366,11 +3237,11 @@ WantedBy=default.target
|
|
|
2366
3237
|
(0, import_node_child_process.spawnSync)("systemctl", ["--user", "daemon-reload"]);
|
|
2367
3238
|
return { success: true, message: "Uninstalled Linux systemd service." };
|
|
2368
3239
|
}
|
|
2369
|
-
return { success: false, message: `Unsupported OS: ${
|
|
3240
|
+
return { success: false, message: `Unsupported OS: ${platform4}` };
|
|
2370
3241
|
}
|
|
2371
3242
|
static status() {
|
|
2372
|
-
const
|
|
2373
|
-
if (
|
|
3243
|
+
const platform4 = os3.platform();
|
|
3244
|
+
if (platform4 === "darwin") {
|
|
2374
3245
|
const res = (0, import_node_child_process.spawnSync)("launchctl", ["list"], { encoding: "utf-8" });
|
|
2375
3246
|
const running = res.stdout && (res.stdout.includes("com.agentgram") || res.stdout.includes("com.rumuze.edit")) || false;
|
|
2376
3247
|
const installed = fs4.existsSync(MACOS_PLIST_PATH) || fs4.existsSync(LEGACY_MACOS_PLIST_PATH);
|
|
@@ -2378,10 +3249,10 @@ WantedBy=default.target
|
|
|
2378
3249
|
return {
|
|
2379
3250
|
installed,
|
|
2380
3251
|
running,
|
|
2381
|
-
system:
|
|
3252
|
+
system: platform4,
|
|
2382
3253
|
path: installed ? activePath : void 0
|
|
2383
3254
|
};
|
|
2384
|
-
} else if (
|
|
3255
|
+
} else if (platform4 === "linux") {
|
|
2385
3256
|
const res = (0, import_node_child_process.spawnSync)("systemctl", ["--user", "is-active", LINUX_SERVICE_NAME], {
|
|
2386
3257
|
encoding: "utf-8"
|
|
2387
3258
|
});
|
|
@@ -2399,11 +3270,11 @@ WantedBy=default.target
|
|
|
2399
3270
|
return {
|
|
2400
3271
|
installed,
|
|
2401
3272
|
running,
|
|
2402
|
-
system:
|
|
3273
|
+
system: platform4,
|
|
2403
3274
|
path: installed ? activePath : void 0
|
|
2404
3275
|
};
|
|
2405
3276
|
}
|
|
2406
|
-
return { installed: false, running: false, system:
|
|
3277
|
+
return { installed: false, running: false, system: platform4 };
|
|
2407
3278
|
}
|
|
2408
3279
|
};
|
|
2409
3280
|
}
|
|
@@ -2459,9 +3330,9 @@ function getPidFilePath() {
|
|
|
2459
3330
|
}
|
|
2460
3331
|
function checkOpenCodeCli() {
|
|
2461
3332
|
try {
|
|
2462
|
-
const isWin =
|
|
3333
|
+
const isWin = os4.platform() === "win32";
|
|
2463
3334
|
const cmd = isWin ? "where" : "which";
|
|
2464
|
-
const res =
|
|
3335
|
+
const res = child_process4.spawnSync(cmd, ["opencode"], { encoding: "utf-8" });
|
|
2465
3336
|
return res.status === 0 && res.stdout.trim().length > 0;
|
|
2466
3337
|
} catch {
|
|
2467
3338
|
return false;
|
|
@@ -2690,7 +3561,7 @@ Please run ${C.bold}${C.cyan}agentgram init${C.reset} to set up your Telegram cr
|
|
|
2690
3561
|
"--engine",
|
|
2691
3562
|
selectedEngine
|
|
2692
3563
|
];
|
|
2693
|
-
const child =
|
|
3564
|
+
const child = child_process4.spawn(process.execPath, spawnArgs, {
|
|
2694
3565
|
cwd: targetDir,
|
|
2695
3566
|
detached: true,
|
|
2696
3567
|
stdio: ["ignore", out, err],
|
|
@@ -2723,15 +3594,22 @@ Please run ${C.bold}${C.cyan}agentgram init${C.reset} to set up your Telegram cr
|
|
|
2723
3594
|
let engineAdapter;
|
|
2724
3595
|
let spawnedOc;
|
|
2725
3596
|
if (selectedEngine === "opencode") {
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
}
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
3597
|
+
const envUrl = process.env.OPENCODE_URL;
|
|
3598
|
+
if (envUrl) {
|
|
3599
|
+
info(`Connecting to configured OpenCode server at: ${C.cyan}${envUrl}${C.reset}`);
|
|
3600
|
+
const ocClient = new OpenCodeClient(envUrl, process.env.OPENCODE_SERVER_PASSWORD, targetDir);
|
|
3601
|
+
engineAdapter = new OpenCodeAdapter(ocClient, targetDir);
|
|
3602
|
+
} else {
|
|
3603
|
+
try {
|
|
3604
|
+
info("Spawning private OpenCode server on loopback...");
|
|
3605
|
+
spawnedOc = await OpenCodeClient.spawnServer(targetDir);
|
|
3606
|
+
engineAdapter = new OpenCodeAdapter(spawnedOc.client, targetDir);
|
|
3607
|
+
success(`OpenCode server online (port: ${spawnedOc.port}).`);
|
|
3608
|
+
} catch (err) {
|
|
3609
|
+
warn(`Could not spawn OpenCode server: ${err.message}`);
|
|
3610
|
+
warn("Resilience mode active: Falling back to Shell CLI Engine so Telegram bot connects immediately.");
|
|
3611
|
+
engineAdapter = new ShellEngineAdapter({ workspaceDir: targetDir, cliCommand: "sh" });
|
|
3612
|
+
}
|
|
2735
3613
|
}
|
|
2736
3614
|
} else if (selectedEngine === "shell" || selectedEngine === "sh" || selectedEngine === "bash") {
|
|
2737
3615
|
engineAdapter = new ShellEngineAdapter({ workspaceDir: targetDir, cliCommand: "sh" });
|
|
@@ -2823,7 +3701,7 @@ function cmdStatus() {
|
|
|
2823
3701
|
info(`System Service (${svc.system}): Not installed`);
|
|
2824
3702
|
}
|
|
2825
3703
|
try {
|
|
2826
|
-
const ps =
|
|
3704
|
+
const ps = child_process4.spawnSync("pgrep", ["-fl", "opencode serve"], { encoding: "utf-8" });
|
|
2827
3705
|
if (ps.status === 0 && ps.stdout.trim()) {
|
|
2828
3706
|
success(`OpenCode Server: Active (${ps.stdout.trim().split("\n")[0]})`);
|
|
2829
3707
|
} else {
|
|
@@ -2924,15 +3802,15 @@ async function runCli(argv = process.argv.slice(2)) {
|
|
|
2924
3802
|
process.exit(1);
|
|
2925
3803
|
}
|
|
2926
3804
|
}
|
|
2927
|
-
var fs5,
|
|
3805
|
+
var fs5, os4, path5, readline2, child_process4, VERSION, C;
|
|
2928
3806
|
var init_cli = __esm({
|
|
2929
3807
|
"src/cli/index.ts"() {
|
|
2930
3808
|
"use strict";
|
|
2931
3809
|
fs5 = __toESM(require("fs"));
|
|
2932
|
-
|
|
3810
|
+
os4 = __toESM(require("os"));
|
|
2933
3811
|
path5 = __toESM(require("path"));
|
|
2934
3812
|
readline2 = __toESM(require("readline"));
|
|
2935
|
-
|
|
3813
|
+
child_process4 = __toESM(require("child_process"));
|
|
2936
3814
|
init_config_manager();
|
|
2937
3815
|
init_telegram_client();
|
|
2938
3816
|
init_opencode_client();
|
|
@@ -2944,7 +3822,7 @@ var init_cli = __esm({
|
|
|
2944
3822
|
init_shell_adapter();
|
|
2945
3823
|
init_registry2();
|
|
2946
3824
|
init_service_manager();
|
|
2947
|
-
VERSION = "2.0.
|
|
3825
|
+
VERSION = "2.0.4";
|
|
2948
3826
|
C = {
|
|
2949
3827
|
reset: "\x1B[0m",
|
|
2950
3828
|
bold: "\x1B[1m",
|
|
@@ -2985,7 +3863,7 @@ __export(index_exports, {
|
|
|
2985
3863
|
computeWorkspaceId: () => computeWorkspaceId,
|
|
2986
3864
|
decidePermission: () => decidePermission,
|
|
2987
3865
|
ensureConfigDirs: () => ensureConfigDirs,
|
|
2988
|
-
escapeHtml: () =>
|
|
3866
|
+
escapeHtml: () => escapeHtml,
|
|
2989
3867
|
fromTelegramMarkup: () => fromTelegramMarkup,
|
|
2990
3868
|
getEntryPoint: () => getEntryPoint,
|
|
2991
3869
|
getFreePort: () => getFreePort,
|